Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[cdt-patch] Parser Symbol Table: prefix lookup

First pass at prefix lookup.

Core:
In prefix lookup, the lookup does not stop when a symbol is found, also 
abiguity resolution is modified.
        Add IContainerSymbol.prefixLookup (signature subject to change)
        Add ParserSymbolTable.LookupMode, an enum with 2 values: NORMAL, 
PREFIX
        In prefix mode, the lookup does not stop when a symbol is found.

Tests:

        ParserSymbolTableTest.testBug46882
        ParserSymbolTableTest.testPrefixLookup_Unqualified
        ParserSymbolTableTest.testPrefixLookup_Qualified
        ParserSymbolTableTest.testPrefixLookup_Inheritance

Tested on windows.

-Andrew
Index: parser/ChangeLog
===================================================================
retrieving revision 1.163
diff -u -r1.163 ChangeLog
--- parser/ChangeLog	20 Nov 2003 15:22:56 -0000	1.163
+++ parser/ChangeLog	27 Nov 2003 16:58:47 -0000
@@ -1,3 +1,9 @@
+2003-11-27 Andrew Niefer
+	Initial changes to support prefix lookup
+	Add IContainerSymbol.prefixLookup (signature subject to change)
+	Add ParserSymbolTable.LookupMode, an enum with 2 values: NORMAL, PREFIX
+	In prefix mode, the lookup does not stop when a symbol is found.
+
 2003-11-18 Andrew Niefer
 	Refactor PST: Split Declaration into 4 classes : ContainerSymbol, DerivableContainerSymbol, ParameterizedContainerSymbol,
 	SpecializedSymbol.  Move these along with BasicSymbol & TemplateInstance to no longer be nested in ParserSymbolTable.
Index: parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java
===================================================================
retrieving revision 1.1
diff -u -r1.1 ContainerSymbol.java
--- parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java	20 Nov 2003 15:22:56 -0000	1.1
+++ parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java	27 Nov 2003 16:58:51 -0000
@@ -212,37 +212,44 @@
 
 		//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 @@
 			}
 		}
 		
-		ParserSymbolTable.lookupInContained( data, container );
+		data.foundItems = ParserSymbolTable.lookupInContained( data, container );
 	
 		return ParserSymbolTable.resolveAmbiguities( data );
 	}
@@ -349,7 +356,7 @@
 		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 @@
 		//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 @@
 		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)
 	 */
Index: parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java
===================================================================
retrieving revision 1.1
diff -u -r1.1 DerivableContainerSymbol.java
--- parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java	20 Nov 2003 15:22:56 -0000	1.1
+++ parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java	27 Nov 2003 16:58:52 -0000
@@ -17,6 +17,7 @@
 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 @@
 		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() );
Index: parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java
===================================================================
retrieving revision 1.7
diff -u -r1.7 IContainerSymbol.java
--- parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java	20 Nov 2003 15:22:56 -0000	1.7
+++ parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java	27 Nov 2003 16:58:52 -0000
@@ -39,6 +39,8 @@
 			
 	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;
Index: parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java
===================================================================
retrieving revision 1.26
diff -u -r1.26 ParserSymbolTable.java
--- parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java	20 Nov 2003 15:22:56 -0000	1.26
+++ parser/org/eclipse/cdt/internal/core/parser/pst/ParserSymbolTable.java	27 Nov 2003 16:58:53 -0000
@@ -22,6 +22,7 @@
 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 @@
 		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 @@
 
 			//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 @@
 			}
 		}
 		
-		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 @@
 	 * 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 @@
 			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() );
 				}
@@ -227,14 +236,47 @@
 	}
 	
 	/**
+	 * @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
 	 * @return List
 	 * 
 	 * 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 @@
 		
 		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 );
+		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 );
+			}
 						
-					foundSomething = true;
-				}
+			if( iterator != null && iterator.hasNext() ){
+				name = (String) iterator.next();
 			} 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;
-					} 
-				}
+				name = null;
 			}
-		}
-
-		if( foundSomething ){
-			return foundSomething;
+		} 
+		
+		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 @@
 		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 @@
 	 * @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 @@
 		
 		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 @@
 						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 @@
 		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 @@
 		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();
-		
-		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;
-		} 
+		//Iterator iter = data.foundItems.iterator();
 		
-		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();
-		
-		int numFunctions = ( functionList == null ) ? 0 : functionList.size();
+		LinkedList functionList = new LinkedList();
 		
-		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( object instanceof List ){
+			functionList.addAll( (List) object );
+		} else {
+			ISymbol symbol = (ISymbol) object;
+			if( symbol.isType( TypeInfo.t_function ) ){
+				functionList.add( symbol );
+			} else {
+				return symbol;
 			}
 		}
 		
-		if( obj != null && !ambiguous ){
-			if( numFunctions > 0 ){
-				ambiguous = true;
+		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 {
-				return obj;
+				throw new ParserSymbolTableException( ParserSymbolTableException.r_UnableToResolveFunction );
 			}
-		} 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 );
 		} else {
-			return cls;
+			return resolveFunction( data, functionList );
 		}
 	}
 
@@ -1549,7 +1634,7 @@
 					data.parameters = params;
 					data.forUserDefinedConversion = true;
 					
-					lookupInContained( data, (IContainerSymbol) sourceDecl );
+					data.foundItems = lookupInContained( data, (IContainerSymbol) sourceDecl );
 					conversion = (IParameterizedSymbol)resolveAmbiguities( data );	
 				}
 			}
@@ -2089,7 +2174,15 @@
 	}
 	
 
-	
+	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 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;
Index: ChangeLog
===================================================================
retrieving revision 1.144
diff -u -r1.144 ChangeLog
--- ChangeLog	20 Nov 2003 15:23:01 -0000	1.144
+++ ChangeLog	27 Nov 2003 16:58:25 -0000
@@ -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.
 
Index: parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java
===================================================================
retrieving revision 1.24
diff -u -r1.24 ParserSymbolTableTest.java
--- parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java	20 Nov 2003 15:23:01 -0000	1.24
+++ parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java	27 Nov 2003 16:58:28 -0000
@@ -13,6 +13,7 @@
 
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
 import junit.framework.TestCase;
@@ -688,6 +689,8 @@
 		}
 		
 		look = f.lookupNestedNameSpecifier("N");
+		assertEquals( look, nsN );
+		
 		look = ((IContainerSymbol) look).qualifiedLookup("i"); //ok
 		assertEquals( look, nsN_i );
 	}
@@ -804,6 +807,8 @@
 		compUnit.addSymbol(f);
 		
 		IContainerSymbol lookA = f.lookupNestedNameSpecifier("A");
+		assertEquals( lookA, nsA );
+		
 		ISymbol look = lookA.qualifiedLookup("a");
 		assertEquals( look, a );
 		
@@ -2938,5 +2943,169 @@
 		
 		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 ) );
+	}
+	
 }
 

Back to the top