diff --git a/core/org.eclipse.cdt.core.tests/ChangeLog b/core/org.eclipse.cdt.core.tests/ChangeLog index cdc5146251b..cbed9e1e479 100644 --- a/core/org.eclipse.cdt.core.tests/ChangeLog +++ b/core/org.eclipse.cdt.core.tests/ChangeLog @@ -1,3 +1,10 @@ +2003-11-27 Andrew Niefer + tests for Symbol table prefix lookup + ParserSymbolTableTest.testBug46882 + ParserSymbolTableTest.testPrefixLookup_Unqualified + ParserSymbolTableTest.testPrefixLookup_Qualified + ParserSymbolTableTest.testPrefixLookup_Inheritance + 2003-11-18 Andrew Niefer update ParserSymbolTableTest to reflect refactoring of Declaration into 4 separate classes. diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java index 8e5bb3dd9c9..13ce26a1dbc 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.core.parser.tests; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.Map; import junit.framework.TestCase; @@ -688,6 +689,8 @@ public class ParserSymbolTableTest extends TestCase { } look = f.lookupNestedNameSpecifier("N"); + assertEquals( look, nsN ); + look = ((IContainerSymbol) look).qualifiedLookup("i"); //ok assertEquals( look, nsN_i ); } @@ -804,6 +807,8 @@ public class ParserSymbolTableTest extends TestCase { compUnit.addSymbol(f); IContainerSymbol lookA = f.lookupNestedNameSpecifier("A"); + assertEquals( lookA, nsA ); + ISymbol look = lookA.qualifiedLookup("a"); assertEquals( look, a ); @@ -2938,5 +2943,169 @@ public class ParserSymbolTableTest extends TestCase { assertEquals( look, init2 ); } + + /** + * class A { + * void f( int ) {} + * void f( ) {} + * }; + * class B : public A { + * void f( char ) { } + * } b; + * + * b.f( 1 ); //calls B::f + * b.f(); //error + * @throws Exception + */ + public void testBug46882() throws Exception{ + newTable(); + + IDerivableContainerSymbol A = table.newDerivableContainerSymbol( "A", TypeInfo.t_class ); + + table.getCompilationUnit().addSymbol( A ); + + IParameterizedSymbol f1 = table.newParameterizedSymbol( "f", TypeInfo.t_function ); + f1.addParameter( TypeInfo.t_int, 0, null, false ); + A.addSymbol( f1 ); + + IParameterizedSymbol f2 = table.newParameterizedSymbol( "f", TypeInfo.t_function ); + A.addSymbol( f2 ); + + IDerivableContainerSymbol B = table.newDerivableContainerSymbol( "B", TypeInfo.t_class ); + B.addParent( A ); + + table.getCompilationUnit().addSymbol( B ); + + IParameterizedSymbol f3 = table.newParameterizedSymbol( "f", TypeInfo.t_function ); + f3.addParameter( TypeInfo.t_char, 0, null, false ); + B.addSymbol( f3 ); + + List params = new LinkedList(); + params.add( new TypeInfo( TypeInfo.t_int, 0, null ) ); + + ISymbol look = B.qualifiedFunctionLookup( "f", params ); + assertEquals( look, f3 ); + + params.clear(); + look = B.qualifiedFunctionLookup( "f", params ); + assertEquals( look, null ); + } + + /** + * int aVar; + * void foo( ) { + * int anotherVar; + * a(CTRL+SPACE) + * } + */ + public void testPrefixLookup_Unqualified() throws Exception { + newTable(); + + ISymbol aVar = table.newSymbol( "aVar", TypeInfo.t_int ); + table.getCompilationUnit().addSymbol( aVar ); + + IParameterizedSymbol foo = table.newParameterizedSymbol( "foo", TypeInfo.t_function ); + table.getCompilationUnit().addSymbol( foo ); + + ISymbol anotherVar = table.newSymbol( "anotherVar", TypeInfo.t_int ); + foo.addSymbol( anotherVar ); + + List results = foo.prefixLookup( TypeInfo.t_any, "a", false ); + assertTrue( results != null ); + assertEquals( results.size(), 2 ); + + assertTrue( results.contains( aVar ) ); + assertTrue( results.contains( anotherVar ) ); + } + + /** + * int aVar; //not a member of D, not reported + * + * class D{ + * int aField; + * void aMethod(); + * }; + * + * D d; + * d.a(CTRL+SPACE) + */ + public void testPrefixLookup_Qualified() throws Exception { + newTable(); + + ISymbol aVar = table.newSymbol( "aVar", TypeInfo.t_int ); + table.getCompilationUnit().addSymbol( aVar ); + + IDerivableContainerSymbol D = table.newDerivableContainerSymbol( "D", TypeInfo.t_class ); + table.getCompilationUnit().addSymbol( D ); + + ISymbol aField = table.newSymbol( "aField", TypeInfo.t_int ); + IParameterizedSymbol aMethod = table.newParameterizedSymbol( "aMethod", TypeInfo.t_function ); + + D.addSymbol( aField ); + D.addSymbol( aMethod ); + + List results = D.prefixLookup( TypeInfo.t_any, "a", true ); + + assertTrue( results != null ); + assertEquals( results.size(), 2 ); + + assertTrue( !results.contains( aVar ) ); + assertTrue( results.contains( aField ) ); + assertTrue( results.contains( aMethod ) ); + } + + /** + * class A { + * int aVar + * int anotherVar; //hidden, not reported + * void af (); //hidden, not reported + * }; + * + * class B : public A { + * int anotherVar; + * void af( char ); + * } b; + * + * b.a(CTRL+SPACE) + * @throws Exception + */ + public void testPrefixLookup_Inheritance() throws Exception { + newTable(); + + IDerivableContainerSymbol A = table.newDerivableContainerSymbol( "A", TypeInfo.t_class ); + table.getCompilationUnit().addSymbol( A ); + + ISymbol aVar = table.newSymbol( "aVar", TypeInfo.t_int ); + ISymbol anotherVar1 = table.newSymbol( "anotherVar", TypeInfo.t_int ); + A.addSymbol( aVar ); + A.addSymbol( anotherVar1 ); + + IParameterizedSymbol af1 = table.newParameterizedSymbol( "af", TypeInfo.t_function ); + A.addSymbol( af1 ); + + IDerivableContainerSymbol B = table.newDerivableContainerSymbol( "B", TypeInfo.t_class ); + B.addParent( A ); + + table.getCompilationUnit().addSymbol( B ); + + ISymbol anotherVar2 = table.newSymbol( "anotherVar", TypeInfo.t_int ); + B.addSymbol( anotherVar2 ); + + IParameterizedSymbol af2 = table.newParameterizedSymbol( "af", TypeInfo.t_function ); + af2.addParameter( TypeInfo.t_char, 0, null, false ); + B.addSymbol( af2 ); + + + List results = B.prefixLookup( TypeInfo.t_any, "a", true ); + + assertTrue( results != null ); + assertEquals( results.size(), 3 ); + assertTrue( ! results.contains( anotherVar1 ) ); + assertTrue( ! results.contains( af1 ) ); + assertTrue( results.contains( aVar ) ); + assertTrue( results.contains( anotherVar2 ) ); + assertTrue( results.contains( af2 ) ); + } + } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java index 53cfd567b85..ca5af515945 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java @@ -212,37 +212,44 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol { //figure out which declaration we are talking about, if it is a set of functions, //then they will be in data.foundItems (since we provided no parameter info); - ISymbol obj = null; + ISymbol symbol = null; + ISymbol clone = null; + Iterator iter = null; + try{ - obj = ParserSymbolTable.resolveAmbiguities( data ); + symbol = ParserSymbolTable.resolveAmbiguities( data ); } catch ( ParserSymbolTableException e ) { if( e.reason != ParserSymbolTableException.r_UnableToResolveFunction ){ throw e; } } - if( data.foundItems == null ){ + if( symbol == null && (data.foundItems == null || data.foundItems.isEmpty()) ){ throw new ParserSymbolTableException( ParserSymbolTableException.r_InvalidUsing ); } - ISymbol clone = null; + if( symbol == null ){ + Object object = data.foundItems.get( data.name ); + iter = ( object instanceof List ) ? ((List) object).iterator() : null; + symbol = ( iter != null && iter.hasNext() ) ? (ISymbol)iter.next() : null; + } - //if obj != null, then that is the only object to consider, so size is 1, - //otherwise we consider the foundItems set - int size = ( obj == null ) ? data.foundItems.size() : 1; - Iterator iter = data.foundItems.iterator(); - for( int i = size; i > 0; i-- ){ - obj = ( obj != null && size == 1 ) ? obj : (ISymbol) iter.next(); - - if( ParserSymbolTable.okToAddUsingDeclaration( obj, this ) ){ - clone = (BasicSymbol) obj.clone(); //7.3.3-9 + while( symbol != null ){ + if( ParserSymbolTable.okToAddUsingDeclaration( symbol, this ) ){ + clone = (ISymbol) symbol.clone(); //7.3.3-9 addSymbol( clone ); } else { throw new ParserSymbolTableException( ParserSymbolTableException.r_InvalidUsing ); } + + if( iter != null && iter.hasNext() ){ + symbol = (ISymbol) iter.next(); + } else { + symbol = null; + } } - - return ( size == 1 ) ? clone : null; + + return clone; } /* (non-Javadoc) @@ -322,7 +329,7 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol { } } - ParserSymbolTable.lookupInContained( data, container ); + data.foundItems = ParserSymbolTable.lookupInContained( data, container ); return ParserSymbolTable.resolveAmbiguities( data ); } @@ -349,7 +356,7 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol { LookupData data = new LookupData( name, TypeInfo.t_namespace, getTemplateInstance() ); data.upperType = TypeInfo.t_union; - ParserSymbolTable.lookupInContained( data, inSymbol ); + data.foundItems = ParserSymbolTable.lookupInContained( data, inSymbol ); if( data.foundItems != null ){ foundSymbol = (ISymbol) ParserSymbolTable.resolveAmbiguities( data );//, data.foundItems ); @@ -455,9 +462,9 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol { //if we haven't found anything, or what we found is not a class member, consider the //associated scopes if( found == null || found.getContainingSymbol().getType() != TypeInfo.t_class ){ - if( found != null ){ - data.foundItems.add( found ); - } +// if( found != null ){ +// data.foundItems.add( found ); +// } IContainerSymbol associatedScope; //dump the hash to an array and iterate over the array because we @@ -539,6 +546,34 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol { return null; } + public List prefixLookup( TypeInfo.eType type, String prefix, boolean qualified ) throws ParserSymbolTableException{ + LookupData data = new LookupData( prefix, type, getTemplateInstance() ); + data.qualified = qualified; + data.mode = ParserSymbolTable.LookupMode.PREFIX; + + ParserSymbolTable.lookup( data, this ); + + if( data.foundItems == null || data.foundItems.isEmpty() ){ + return null; + } else { + List list = new LinkedList(); + + Iterator iter = data.foundItems.keySet().iterator(); + Object obj = null; + while( iter.hasNext() ){ + obj = data.foundItems.get( iter.next() ); + + if( obj instanceof List ){ + list.addAll( (List) obj ); + } else{ + list.add( obj ); + } + } + + return list; + } + } + /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#instantiate(java.util.List) */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java index 27982b5f207..797f7ef67b2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java @@ -17,6 +17,7 @@ package org.eclipse.cdt.internal.core.parser.pst; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.Map; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; @@ -189,11 +190,19 @@ public class DerivableContainerSymbol extends ContainerSymbol implements IDeriva if( obj.getContainingSymbol().isType( TypeInfo.t_class, TypeInfo.t_union ) ){ //check to see if there is already a this object, since using declarations //of function will have them from the original declaration + boolean foundThis = false; + LookupData data = new LookupData( ParserSymbolTable.THIS, TypeInfo.t_any, null ); - ParserSymbolTable.lookupInContained( data, obj ); + try { + Map map = ParserSymbolTable.lookupInContained( data, obj ); + foundThis = map.containsKey( data.name ); + } catch (ParserSymbolTableException e) { + return false; + } + //if we didn't find "this" then foundItems will still be null, no need to actually //check its contents - if( data.foundItems == null ){ + if( !foundThis ){ ISymbol thisObj = getSymbolTable().newSymbol( ParserSymbolTable.THIS, TypeInfo.t_type ); thisObj.setTypeSymbol( obj.getContainingSymbol() ); //thisObj.setCVQualifier( obj.getCVQualifier() ); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java index d4324a9a220..d936bb02886 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java @@ -39,6 +39,8 @@ public interface IContainerSymbol extends ISymbol { public Map getContainedSymbols(); + public List prefixLookup( TypeInfo.eType type, String prefix, boolean qualified ) throws ParserSymbolTableException; + public ISymbol elaboratedLookup( TypeInfo.eType type, String name ) throws ParserSymbolTableException; public ISymbol lookup( String name ) throws ParserSymbolTableException; public ISymbol lookupMemberForDefinition( String name ) throws ParserSymbolTableException; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java index a1574795cfb..a0a08373a19 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java @@ -22,6 +22,7 @@ import java.util.ListIterator; import java.util.Map; import java.util.Set; +import org.eclipse.cdt.core.parser.Enum; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; import org.eclipse.cdt.internal.core.parser.pst.TypeInfo.PtrOp; @@ -105,7 +106,12 @@ public class ParserSymbolTable { LinkedList transitives = new LinkedList(); //list of transitive using directives //if this name define in this scope? - lookupInContained( data, inSymbol ); + Map map = lookupInContained( data, inSymbol ); + if( data.foundItems == null || data.foundItems.isEmpty() ){ + data.foundItems = map; + } else { + mergeResults( data, data.foundItems, map ); + } if( inSymbol.getSymbolTable().getLanguage() == ParserLanguage.CPP && !data.ignoreUsingDirectives ) @@ -120,7 +126,7 @@ public class ParserSymbolTable { //if we are doing a qualified lookup, only process using directives if //we haven't found the name yet (and if we aren't ignoring them). - if( !data.qualified || data.foundItems == null ){ + if( !data.qualified || data.foundItems == null || data.foundItems.isEmpty() ){ processDirectives( inSymbol, data, transitives ); if( inSymbol.hasUsingDirectives() ){ @@ -139,25 +145,26 @@ public class ParserSymbolTable { } } - if( data.foundItems != null || data.stopAt == inSymbol ){ + if( data.mode == LookupMode.NORMAL && ( !data.foundItems.isEmpty() || data.stopAt == inSymbol ) ){ return; } if( inSymbol instanceof IDerivableContainerSymbol ){ //if we still havn't found it, check any parents we have - data.visited.clear(); //each virtual base class is searched at most once - symbol = lookupInParents( data, (IDerivableContainerSymbol)inSymbol ); - - //there is a resolveAmbiguities inside LookupInParents, which means if we found - //something the foundItems set will be non-null, but empty. So, add the decl into - //the foundItems set - if( symbol != null ){ - data.foundItems.add( symbol ); + data.visited.clear(); //each virtual base class is searched at most once + map = lookupInParents( data, (IDerivableContainerSymbol)inSymbol ); + + if( data.foundItems == null || data.foundItems.isEmpty() ){ + data.foundItems = map; + } else { + mergeInheritedResults( data.foundItems, map ); } } //if still not found, check our containing scope. - if( data.foundItems == null && inSymbol.getContainingSymbol() != null ){ + if( ( data.foundItems == null || data.foundItems.isEmpty() || ( data.mode == LookupMode.PREFIX && !data.qualified ) ) + && inSymbol.getContainingSymbol() != null ) + { lookup( data, inSymbol.getContainingSymbol() ); } @@ -183,7 +190,7 @@ public class ParserSymbolTable { * directives, the effect is as if the using-directives from the second * namespace also appeared in the first. */ - static private void lookupInNominated( LookupData data, IContainerSymbol symbol, LinkedList transitiveDirectives ){ + static private void lookupInNominated( LookupData data, IContainerSymbol symbol, LinkedList transitiveDirectives ) throws ParserSymbolTableException{ //if the data.usingDirectives is empty, there is nothing to do. if( data.usingDirectives == null ){ return; @@ -212,11 +219,13 @@ public class ParserSymbolTable { if( !data.visited.contains( temp ) ){ data.visited.add( temp ); - foundSomething = lookupInContained( data, temp ); - + Map map = lookupInContained( data, temp ); + foundSomething = !map.isEmpty(); + mergeResults( data, data.foundItems, map ); + //only consider the transitive using directives if we are an unqualified //lookup, or we didn't find the name in decl - if( (!data.qualified || !foundSomething ) && temp.getUsingDirectives() != null ){ + if( (!data.qualified || !foundSomething || data.mode == LookupMode.PREFIX ) && temp.getUsingDirectives() != null ){ //name wasn't found, add transitive using directives for later consideration transitiveDirectives.addAll( temp.getUsingDirectives() ); } @@ -226,6 +235,38 @@ public class ParserSymbolTable { return; } + /** + * @param map + * @param map2 + */ + private static void mergeResults( LookupData data, Map resultMap, Map map ) throws ParserSymbolTableException { + if( resultMap == null || map == null || map.isEmpty() ){ + return; + } + + Iterator keyIterator = map.keySet().iterator(); + Object key = null; + while( keyIterator.hasNext() ){ + key = keyIterator.next(); + if( resultMap.containsKey( key ) ){ + List list = new LinkedList(); + Object obj = resultMap.get( key ); + + if ( obj instanceof List ) list.addAll( (List) obj ); + else list.add( obj ); + + obj = map.get( key ); + + if( obj instanceof List ) list.addAll( (List) obj ); + else list.add( obj ); + + resultMap.put( key, collectSymbol( data, list ) ); + } else { + resultMap.put( key, map.get( key ) ); + } + } + } + /** * function LookupInContained * @param data @@ -233,8 +274,9 @@ public class ParserSymbolTable { * * Look for data.name in our collection _containedDeclarations */ - protected static boolean lookupInContained( LookupData data, IContainerSymbol lookIn ){ - + protected static Map lookupInContained( LookupData data, IContainerSymbol lookIn ) throws ParserSymbolTableException{ + Map found = new HashMap(); + boolean foundSomething = false; ISymbol temp = null; Object obj = null; @@ -246,78 +288,63 @@ public class ParserSymbolTable { Map declarations = lookIn.getContainedSymbols(); - obj = ( declarations != null ) ? declarations.get( data.name ) : null; - - if( obj != null ){ - //the contained declarations map either to a Declaration object, or to a list - //of declaration objects. - if( obj instanceof ISymbol ){ - temp = (ISymbol) obj; - //if( ((ISymbol)obj).isType( data.type, data.upperType ) ){ - if( checkType( data, temp, data.type, data.upperType ) ){ - if( data.foundItems == null ){ - data.foundItems = new HashSet(); - } - if( temp.isTemplateMember() ) - data.foundItems.add( new TemplateInstance( temp.getSymbolTable(), temp, data.templateInstance.getArgumentMap() ) ); - else - data.foundItems.add( temp ); - - foundSomething = true; - } - } else { - //we have to filter on type so can't just add the list whole to the fount set - LinkedList objList = (LinkedList)obj; - Iterator iter = objList.iterator(); - int size = objList.size(); - - for( int i = 0; i < size; i++ ){ - temp = (ISymbol) iter.next(); - - //if( temp.isType( data.type, data.upperType ) ){ - if( checkType( data, temp, data.type, data.upperType ) ){ - if( data.foundItems == null ){ - data.foundItems = new HashSet(); - } - if( temp.isTemplateMember() ) - data.foundItems.add( new TemplateInstance( temp.getSymbolTable(), temp, data.templateInstance.getArgumentMap() ) ); - else - data.foundItems.add(temp); - foundSomething = true; - } - } + Iterator iterator = ( data.mode == LookupMode.PREFIX ) ? declarations.keySet().iterator() : null; + String name = ( iterator != null && iterator.hasNext() ) ? (String) iterator.next() : data.name; + + while( name != null ) { + if( nameMatches( data, name ) ){ + obj = ( declarations != null ) ? declarations.get( name ) : null; + + obj = collectSymbol( data, obj ); + + if( obj != null ) + found.put( name, obj ); } - } - - if( foundSomething ){ - return foundSomething; + + if( iterator != null && iterator.hasNext() ){ + name = (String) iterator.next(); + } else { + name = null; + } + } + + if( !found.isEmpty() && data.mode == LookupMode.NORMAL ){ + return found; } if( lookIn instanceof IParameterizedSymbol ){ Map parameters = ((IParameterizedSymbol)lookIn).getParameterMap(); if( parameters != null ){ - obj = parameters.get( data.name ); - //if( obj != null && ((ISymbol)obj).isType( data.type, data.upperType ) ){ - if( obj != null && checkType( data, (ISymbol)obj, data.type, data.upperType ) ){ - if( data.foundItems == null ){ - data.foundItems = new HashSet(); + iterator = ( data.mode == LookupMode.PREFIX ) ? parameters.keySet().iterator() : null; + name = ( iterator != null && iterator.hasNext() ) ? (String) iterator.next() : data.name; + while( name != null ){ + if( nameMatches( data, name ) ){ + obj = parameters.get( data.name ); + obj = collectSymbol( data, obj ); + if( obj != null ){ + found.put( name, obj ); + } } - ISymbol symbol = (ISymbol) obj; - - if( symbol.isTemplateMember() && data.templateInstance != null ){ - data.foundItems.add( new TemplateInstance( symbol.getSymbolTable(), symbol, data.templateInstance.getArgumentMap() ) ); + if( iterator != null && iterator.hasNext() ){ + name = (String) iterator.next(); } else { - data.foundItems.add( symbol ); + name = null; } - - foundSomething = true; } + } } - return foundSomething; + return found; } + private static boolean nameMatches( LookupData data, String name ){ + if( data.mode == LookupMode.PREFIX ){ + return name.startsWith( data.name ); + } else { + return name.equals( data.name ); + } + } private static boolean checkType( LookupData data, ISymbol symbol, TypeInfo.eType type, TypeInfo.eType upperType ){ if( data.templateInstance != null && symbol.isTemplateMember() ){ if( symbol.isType( TypeInfo.t_type ) ){ @@ -331,6 +358,100 @@ public class ParserSymbolTable { return symbol.isType( type, upperType ); } + private static Object collectSymbol(LookupData data, Object object ) throws ParserSymbolTableException { + if( object == null ){ + return null; + } + + ISymbol foundSymbol = null; + + Iterator iter = ( object instanceof List ) ? ((List)object).iterator() : null; + ISymbol symbol = ( iter != null ) ? (ISymbol) iter.next() : (ISymbol) object; + + List functionList = new LinkedList(); + ISymbol obj = null; + IContainerSymbol cls = null; + + while( symbol != null ){ + if( checkType( data, symbol, data.type, data.upperType ) ){ + if( symbol.isTemplateMember() && data.templateInstance != null ) + foundSymbol = new TemplateInstance( symbol.getSymbolTable(), symbol, data.templateInstance.getArgumentMap() ); + else + foundSymbol = symbol; + + if( foundSymbol.isType( TypeInfo.t_function ) ){ + functionList.add( foundSymbol ); + } else { + //if this is a class-name, other stuff hides it + if( foundSymbol.isType( TypeInfo.t_class, TypeInfo.t_enumeration ) ){ + if( cls == null ){ + cls = (IContainerSymbol) foundSymbol; + } else { + if( cls.getTypeInfo().isForwardDeclaration() && cls.getTypeSymbol() == foundSymbol ){ + //cls is a forward declaration of decl, we want decl. + cls = (IContainerSymbol) foundSymbol; + } else if( foundSymbol.getTypeInfo().isForwardDeclaration() && foundSymbol.getTypeSymbol() == cls ){ + //decl is a forward declaration of cls, we already have what we want (cls) + } else { + throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + } + } + } else { + //an object, can only have one of these + if( obj == null ){ + obj = foundSymbol; + } else { + throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + } + } + } + } + + if( iter != null ){ + symbol = iter.hasNext() ? (ISymbol) iter.next() : null; + } else { + symbol = null; + } + } + + int numFunctions = functionList.size(); + + boolean ambiguous = false; + + if( cls != null ){ + //the class is only hidden by other stuff if they are from the same scope + if( obj != null && cls.getContainingSymbol() != obj.getContainingSymbol()){ + ambiguous = true; + } + if( functionList != null ){ + Iterator fnIter = functionList.iterator(); + IParameterizedSymbol fn = null; + for( int i = numFunctions; i > 0; i-- ){ + fn = (IParameterizedSymbol) fnIter.next(); + if( cls.getContainingSymbol()!= fn.getContainingSymbol()){ + ambiguous = true; + break; + } + } + } + } + + if( obj != null && !ambiguous ){ + if( numFunctions > 0 ){ + ambiguous = true; + } else { + return obj; + } + } else if( numFunctions > 0 ) { + return functionList; + } + + if( ambiguous ){ + throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + } else { + return cls; + } + } /** * * @param data @@ -338,7 +459,7 @@ public class ParserSymbolTable { * @return Declaration * @throws ParserSymbolTableException */ - private static ISymbol lookupInParents( LookupData data, ISymbol lookIn ) throws ParserSymbolTableException{ + private static Map lookupInParents( LookupData data, ISymbol lookIn ) throws ParserSymbolTableException{ IDerivableContainerSymbol container = null; /*if( lookIn instanceof TemplateInstance ){ @@ -351,8 +472,9 @@ public class ParserSymbolTable { List scopes = container.getParents(); - ISymbol temp = null; - ISymbol symbol = null; + Map temp = null; + Map symbol = null; + Map inherited = null; Iterator iterator = null; IDerivableContainerSymbol.IParentSymbol wrapper = null; @@ -396,39 +518,39 @@ public class ParserSymbolTable { data.templateInstance = (TemplateInstance) parent; ISymbol instance = ((TemplateInstance)parent).getInstantiatedSymbol(); if( instance instanceof IContainerSymbol ) - lookupInContained( data, (IContainerSymbol)instance ); + temp = lookupInContained( data, (IContainerSymbol)instance ); else throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplate ); data.templateInstance = tempInstance; } else if( parent instanceof IDerivableContainerSymbol ){ - lookupInContained( data, (IDerivableContainerSymbol) parent ); + temp = lookupInContained( data, (IDerivableContainerSymbol) parent ); } else { throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo ); } - temp = resolveAmbiguities( data ); - if( temp == null ){ - temp = lookupInParents( data, parent ); + + if( temp.isEmpty() || data.mode == LookupMode.PREFIX ){ + inherited = lookupInParents( data, parent ); + mergeInheritedResults( temp, inherited ); } } else { throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance ); } } - if( temp != null && temp.isType( data.type ) ){ - - if( symbol == null ){ + if( temp != null && !temp.isEmpty() ){ + if( symbol == null || symbol.isEmpty() ){ symbol = temp; - } else if ( temp != null ) { - //it is not ambiguous if temp & decl are the same thing and it is static - //or an enumerator - TypeInfo type = temp.getTypeInfo(); - - if( symbol == temp && ( type.checkBit( TypeInfo.isStatic ) || type.isType( TypeInfo.t_enumerator ) ) ){ - temp = null; - } else { - throw( new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ) ); + } else if ( temp != null && !temp.isEmpty() ) { + Iterator iter = temp.keySet().iterator(); + Object key = null; + while( iter.hasNext() ){ + key = iter.next(); + if( symbol.containsKey( key ) ){ + checkAmbiguity( symbol.get( key ), temp.get( key ) ); + } else { + symbol.put( key, temp.get( key ) ); + } } - } } else { temp = null; //reset temp for next iteration @@ -440,6 +562,50 @@ public class ParserSymbolTable { return symbol; } + private static void checkAmbiguity( Object obj1, Object obj2 ) throws ParserSymbolTableException{ + //it is not ambiguous if they are the same thing and it is static or an enumerator + if( obj1 == obj2 ){ + + Iterator iter = ( obj1 instanceof List ) ? ((List) obj1).iterator() : null; + ISymbol symbol = ( iter != null ) ? (ISymbol) iter.next() : ( ISymbol )obj1; + while( symbol != null ) { + TypeInfo type = ((ISymbol)obj1).getTypeInfo(); + if( !type.checkBit( TypeInfo.isStatic ) && !type.isType( TypeInfo.t_enumerator ) ){ + throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + } + + if( iter != null && iter.hasNext() ){ + symbol = (ISymbol) iter.next(); + } else { + symbol = null; + } + } + return; + } + throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + } + + /** + * Symbols in map are added to the resultMap if a symbol with that name does not already exist there + * @param resultMap + * @param map + * @throws ParserSymbolTableException + */ + private static void mergeInheritedResults( Map resultMap, Map map ) throws ParserSymbolTableException{ + if( resultMap == null || map == null || map.isEmpty() ){ + return; + } + + Iterator keyIterator = map.keySet().iterator(); + Object key = null; + while( keyIterator.hasNext() ){ + key = keyIterator.next(); + if( !resultMap.containsKey( key ) ){ + resultMap.put( key, map.get( key ) ); + } + } + } + /** * function isValidOverload * @param origDecl @@ -561,119 +727,38 @@ public class ParserSymbolTable { ISymbol obj = null; IContainerSymbol cls = null; - if( data.foundItems == null ){ + if( data.foundItems == null || data.foundItems.isEmpty() || data.mode == LookupMode.PREFIX ){ return null; } int size = data.foundItems.size(); - Iterator iter = data.foundItems.iterator(); + //Iterator iter = data.foundItems.iterator(); - boolean needDecl = true; - - if( size == 0){ - return null; - } else if (size == 1) { - decl = (ISymbol) iter.next(); - //if it is a function we need to check its parameters - if( !decl.isType( TypeInfo.t_function ) ){ - data.foundItems.clear(); - return decl; - } - needDecl = false; - } - - LinkedList functionList = null; + Object object = data.foundItems.get( data.name ); - for( int i = size; i > 0; i-- ){ - //if we - if( needDecl ){ - decl = (ISymbol) iter.next(); - } else { - needDecl = true; - } - - if( decl.isType( TypeInfo.t_function ) ){ - if( functionList == null){ - functionList = new LinkedList(); - } - functionList.add( decl ); - } else { - //if this is a class-name, other stuff hides it - if( decl.isType( TypeInfo.t_class, TypeInfo.t_enumeration ) ){ - if( cls == null ){ - cls = (IContainerSymbol) decl; - } else { - if( cls.getTypeInfo().isForwardDeclaration() && cls.getTypeSymbol() == decl ){ - //cls is a forward declaration of decl, we want decl. - cls = (IContainerSymbol) decl; - } else if( decl.getTypeInfo().isForwardDeclaration() && decl.getTypeSymbol() == cls ){ - //decl is a forward declaration of cls, we already have what we want (cls) - } else { - throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); - } - } - } else { - //an object, can only have one of these - if( obj == null ){ - obj = decl; - } else { - throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); - } - } - } - - decl = null; - } - - data.foundItems.clear(); + LinkedList functionList = new LinkedList(); - int numFunctions = ( functionList == null ) ? 0 : functionList.size(); - - boolean ambiguous = false; - - if( cls != null ){ - //the class is only hidden by other stuff if they are from the same scope - if( obj != null && cls.getContainingSymbol() != obj.getContainingSymbol()){ - ambiguous = true; - } - if( functionList != null ){ - Iterator fnIter = functionList.iterator(); - IParameterizedSymbol fn = null; - for( int i = numFunctions; i > 0; i-- ){ - fn = (IParameterizedSymbol) fnIter.next(); - if( cls.getContainingSymbol()!= fn.getContainingSymbol()){ - ambiguous = true; - break; - } - } - } - } - - if( obj != null && !ambiguous ){ - if( numFunctions > 0 ){ - ambiguous = true; - } else { - return obj; - } - } else if( numFunctions > 0 ) { - if( data.parameters == null ){ - //we have no parameter information, if we only have one function, return - //that, otherwise we can't decide between them - if( numFunctions == 1){ - return (ISymbol) functionList.getFirst(); - } else { - data.foundItems.addAll( functionList ); - throw new ParserSymbolTableException( ParserSymbolTableException.r_UnableToResolveFunction ); - } - } else { - return resolveFunction( data, functionList ); - } - } - - if( ambiguous ){ - throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ); + if( object instanceof List ){ + functionList.addAll( (List) object ); } else { - return cls; + ISymbol symbol = (ISymbol) object; + if( symbol.isType( TypeInfo.t_function ) ){ + functionList.add( symbol ); + } else { + return symbol; + } + } + + if( data.parameters == null ){ + //we have no parameter information, if we only have one function, return + //that, otherwise we can't decide between them + if( functionList.size() == 1){ + return (ISymbol) functionList.getFirst(); + } else { + throw new ParserSymbolTableException( ParserSymbolTableException.r_UnableToResolveFunction ); + } + } else { + return resolveFunction( data, functionList ); } } @@ -1549,7 +1634,7 @@ public class ParserSymbolTable { data.parameters = params; data.forUserDefinedConversion = true; - lookupInContained( data, (IContainerSymbol) sourceDecl ); + data.foundItems = lookupInContained( data, (IContainerSymbol) sourceDecl ); conversion = (IParameterizedSymbol)resolveAmbiguities( data ); } } @@ -2089,7 +2174,15 @@ public class ParserSymbolTable { } - + static public class LookupMode extends Enum{ + public static final LookupMode PREFIX = new LookupMode( 1 ); + public static final LookupMode NORMAL = new LookupMode( 2 ); + + private LookupMode( int constant) + { + super( constant ); + } + } static protected class LookupData @@ -2111,9 +2204,10 @@ public class ParserSymbolTable { public boolean ignoreUsingDirectives = false; public boolean forUserDefinedConversion = false; - public HashSet foundItems = null; + public Map foundItems = null; public ISymbol templateInstance = null; + public LookupMode mode = LookupMode.NORMAL; public LookupData( String n, TypeInfo.eType t, ISymbol i ){ name = n;