1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Patch for Andrew Niefer.

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
This commit is contained in:
John Camelon 2003-11-28 04:58:00 +00:00
parent 89054fc120
commit 0adb9b9d20
6 changed files with 542 additions and 226 deletions

View file

@ -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 2003-11-18 Andrew Niefer
update ParserSymbolTableTest to reflect refactoring of Declaration into 4 separate classes. update ParserSymbolTableTest to reflect refactoring of Declaration into 4 separate classes.

View file

@ -13,6 +13,7 @@ package org.eclipse.cdt.core.parser.tests;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -688,6 +689,8 @@ public class ParserSymbolTableTest extends TestCase {
} }
look = f.lookupNestedNameSpecifier("N"); look = f.lookupNestedNameSpecifier("N");
assertEquals( look, nsN );
look = ((IContainerSymbol) look).qualifiedLookup("i"); //ok look = ((IContainerSymbol) look).qualifiedLookup("i"); //ok
assertEquals( look, nsN_i ); assertEquals( look, nsN_i );
} }
@ -804,6 +807,8 @@ public class ParserSymbolTableTest extends TestCase {
compUnit.addSymbol(f); compUnit.addSymbol(f);
IContainerSymbol lookA = f.lookupNestedNameSpecifier("A"); IContainerSymbol lookA = f.lookupNestedNameSpecifier("A");
assertEquals( lookA, nsA );
ISymbol look = lookA.qualifiedLookup("a"); ISymbol look = lookA.qualifiedLookup("a");
assertEquals( look, a ); assertEquals( look, a );
@ -2938,5 +2943,169 @@ public class ParserSymbolTableTest extends TestCase {
assertEquals( look, init2 ); 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 ) );
}
} }

View file

@ -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, //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); //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{ try{
obj = ParserSymbolTable.resolveAmbiguities( data ); symbol = ParserSymbolTable.resolveAmbiguities( data );
} catch ( ParserSymbolTableException e ) { } catch ( ParserSymbolTableException e ) {
if( e.reason != ParserSymbolTableException.r_UnableToResolveFunction ){ if( e.reason != ParserSymbolTableException.r_UnableToResolveFunction ){
throw e; throw e;
} }
} }
if( data.foundItems == null ){ if( symbol == null && (data.foundItems == null || data.foundItems.isEmpty()) ){
throw new ParserSymbolTableException( ParserSymbolTableException.r_InvalidUsing ); 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, while( symbol != null ){
//otherwise we consider the foundItems set if( ParserSymbolTable.okToAddUsingDeclaration( symbol, this ) ){
int size = ( obj == null ) ? data.foundItems.size() : 1; clone = (ISymbol) symbol.clone(); //7.3.3-9
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
addSymbol( clone ); addSymbol( clone );
} else { } else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_InvalidUsing ); 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) /* (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 ); return ParserSymbolTable.resolveAmbiguities( data );
} }
@ -349,7 +356,7 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol {
LookupData data = new LookupData( name, TypeInfo.t_namespace, getTemplateInstance() ); LookupData data = new LookupData( name, TypeInfo.t_namespace, getTemplateInstance() );
data.upperType = TypeInfo.t_union; data.upperType = TypeInfo.t_union;
ParserSymbolTable.lookupInContained( data, inSymbol ); data.foundItems = ParserSymbolTable.lookupInContained( data, inSymbol );
if( data.foundItems != null ){ if( data.foundItems != null ){
foundSymbol = (ISymbol) ParserSymbolTable.resolveAmbiguities( data );//, data.foundItems ); 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 //if we haven't found anything, or what we found is not a class member, consider the
//associated scopes //associated scopes
if( found == null || found.getContainingSymbol().getType() != TypeInfo.t_class ){ if( found == null || found.getContainingSymbol().getType() != TypeInfo.t_class ){
if( found != null ){ // if( found != null ){
data.foundItems.add( found ); // data.foundItems.add( found );
} // }
IContainerSymbol associatedScope; IContainerSymbol associatedScope;
//dump the hash to an array and iterate over the array because we //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; 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) /* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#instantiate(java.util.List) * @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#instantiate(java.util.List)
*/ */

View file

@ -17,6 +17,7 @@ package org.eclipse.cdt.internal.core.parser.pst;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map;
import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; 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 ) ){ if( obj.getContainingSymbol().isType( TypeInfo.t_class, TypeInfo.t_union ) ){
//check to see if there is already a this object, since using declarations //check to see if there is already a this object, since using declarations
//of function will have them from the original declaration //of function will have them from the original declaration
boolean foundThis = false;
LookupData data = new LookupData( ParserSymbolTable.THIS, TypeInfo.t_any, null ); 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 //if we didn't find "this" then foundItems will still be null, no need to actually
//check its contents //check its contents
if( data.foundItems == null ){ if( !foundThis ){
ISymbol thisObj = getSymbolTable().newSymbol( ParserSymbolTable.THIS, TypeInfo.t_type ); ISymbol thisObj = getSymbolTable().newSymbol( ParserSymbolTable.THIS, TypeInfo.t_type );
thisObj.setTypeSymbol( obj.getContainingSymbol() ); thisObj.setTypeSymbol( obj.getContainingSymbol() );
//thisObj.setCVQualifier( obj.getCVQualifier() ); //thisObj.setCVQualifier( obj.getCVQualifier() );

View file

@ -39,6 +39,8 @@ public interface IContainerSymbol extends ISymbol {
public Map getContainedSymbols(); 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 elaboratedLookup( TypeInfo.eType type, String name ) throws ParserSymbolTableException;
public ISymbol lookup( String name ) throws ParserSymbolTableException; public ISymbol lookup( String name ) throws ParserSymbolTableException;
public ISymbol lookupMemberForDefinition( String name ) throws ParserSymbolTableException; public ISymbol lookupMemberForDefinition( String name ) throws ParserSymbolTableException;

View file

@ -22,6 +22,7 @@ import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.eclipse.cdt.core.parser.Enum;
import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import org.eclipse.cdt.internal.core.parser.pst.TypeInfo.PtrOp; 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 LinkedList transitives = new LinkedList(); //list of transitive using directives
//if this name define in this scope? //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 && if( inSymbol.getSymbolTable().getLanguage() == ParserLanguage.CPP &&
!data.ignoreUsingDirectives ) !data.ignoreUsingDirectives )
@ -120,7 +126,7 @@ public class ParserSymbolTable {
//if we are doing a qualified lookup, only process using directives if //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). //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 ); processDirectives( inSymbol, data, transitives );
if( inSymbol.hasUsingDirectives() ){ 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; return;
} }
if( inSymbol instanceof IDerivableContainerSymbol ){ if( inSymbol instanceof IDerivableContainerSymbol ){
//if we still havn't found it, check any parents we have //if we still havn't found it, check any parents we have
data.visited.clear(); //each virtual base class is searched at most once data.visited.clear(); //each virtual base class is searched at most once
symbol = lookupInParents( data, (IDerivableContainerSymbol)inSymbol ); map = lookupInParents( data, (IDerivableContainerSymbol)inSymbol );
//there is a resolveAmbiguities inside LookupInParents, which means if we found if( data.foundItems == null || data.foundItems.isEmpty() ){
//something the foundItems set will be non-null, but empty. So, add the decl into data.foundItems = map;
//the foundItems set } else {
if( symbol != null ){ mergeInheritedResults( data.foundItems, map );
data.foundItems.add( symbol );
} }
} }
//if still not found, check our containing scope. //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() ); lookup( data, inSymbol.getContainingSymbol() );
} }
@ -183,7 +190,7 @@ public class ParserSymbolTable {
* directives, the effect is as if the using-directives from the second * directives, the effect is as if the using-directives from the second
* namespace also appeared in the first. * 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 the data.usingDirectives is empty, there is nothing to do.
if( data.usingDirectives == null ){ if( data.usingDirectives == null ){
return; return;
@ -212,11 +219,13 @@ public class ParserSymbolTable {
if( !data.visited.contains( temp ) ){ if( !data.visited.contains( temp ) ){
data.visited.add( 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 //only consider the transitive using directives if we are an unqualified
//lookup, or we didn't find the name in decl //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 //name wasn't found, add transitive using directives for later consideration
transitiveDirectives.addAll( temp.getUsingDirectives() ); transitiveDirectives.addAll( temp.getUsingDirectives() );
} }
@ -226,6 +235,38 @@ public class ParserSymbolTable {
return; 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 * function LookupInContained
* @param data * @param data
@ -233,7 +274,8 @@ public class ParserSymbolTable {
* *
* Look for data.name in our collection _containedDeclarations * 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; boolean foundSomething = false;
ISymbol temp = null; ISymbol temp = null;
@ -246,78 +288,63 @@ public class ParserSymbolTable {
Map declarations = lookIn.getContainedSymbols(); Map declarations = lookIn.getContainedSymbols();
obj = ( declarations != null ) ? declarations.get( data.name ) : null; Iterator iterator = ( data.mode == LookupMode.PREFIX ) ? declarations.keySet().iterator() : null;
String name = ( iterator != null && iterator.hasNext() ) ? (String) iterator.next() : data.name;
if( obj != null ){ while( name != null ) {
//the contained declarations map either to a Declaration object, or to a list if( nameMatches( data, name ) ){
//of declaration objects. obj = ( declarations != null ) ? declarations.get( name ) : null;
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; obj = collectSymbol( data, obj );
}
if( obj != null )
found.put( name, obj );
}
if( iterator != null && iterator.hasNext() ){
name = (String) iterator.next();
} else { } else {
//we have to filter on type so can't just add the list whole to the fount set name = null;
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;
}
}
} }
} }
if( foundSomething ){ if( !found.isEmpty() && data.mode == LookupMode.NORMAL ){
return foundSomething; return found;
} }
if( lookIn instanceof IParameterizedSymbol ){ if( lookIn instanceof IParameterizedSymbol ){
Map parameters = ((IParameterizedSymbol)lookIn).getParameterMap(); Map parameters = ((IParameterizedSymbol)lookIn).getParameterMap();
if( parameters != null ){ if( parameters != null ){
obj = parameters.get( data.name ); iterator = ( data.mode == LookupMode.PREFIX ) ? parameters.keySet().iterator() : null;
//if( obj != null && ((ISymbol)obj).isType( data.type, data.upperType ) ){ name = ( iterator != null && iterator.hasNext() ) ? (String) iterator.next() : data.name;
if( obj != null && checkType( data, (ISymbol)obj, data.type, data.upperType ) ){ while( name != null ){
if( data.foundItems == null ){ if( nameMatches( data, name ) ){
data.foundItems = new HashSet(); obj = parameters.get( data.name );
obj = collectSymbol( data, obj );
if( obj != null ){
found.put( name, obj );
}
} }
ISymbol symbol = (ISymbol) obj; if( iterator != null && iterator.hasNext() ){
name = (String) iterator.next();
if( symbol.isTemplateMember() && data.templateInstance != null ){
data.foundItems.add( new TemplateInstance( symbol.getSymbolTable(), symbol, data.templateInstance.getArgumentMap() ) );
} else { } 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 ){ private static boolean checkType( LookupData data, ISymbol symbol, TypeInfo.eType type, TypeInfo.eType upperType ){
if( data.templateInstance != null && symbol.isTemplateMember() ){ if( data.templateInstance != null && symbol.isTemplateMember() ){
if( symbol.isType( TypeInfo.t_type ) ){ if( symbol.isType( TypeInfo.t_type ) ){
@ -331,6 +358,100 @@ public class ParserSymbolTable {
return symbol.isType( type, upperType ); 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 * @param data
@ -338,7 +459,7 @@ public class ParserSymbolTable {
* @return Declaration * @return Declaration
* @throws ParserSymbolTableException * @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; IDerivableContainerSymbol container = null;
/*if( lookIn instanceof TemplateInstance ){ /*if( lookIn instanceof TemplateInstance ){
@ -351,8 +472,9 @@ public class ParserSymbolTable {
List scopes = container.getParents(); List scopes = container.getParents();
ISymbol temp = null; Map temp = null;
ISymbol symbol = null; Map symbol = null;
Map inherited = null;
Iterator iterator = null; Iterator iterator = null;
IDerivableContainerSymbol.IParentSymbol wrapper = null; IDerivableContainerSymbol.IParentSymbol wrapper = null;
@ -396,39 +518,39 @@ public class ParserSymbolTable {
data.templateInstance = (TemplateInstance) parent; data.templateInstance = (TemplateInstance) parent;
ISymbol instance = ((TemplateInstance)parent).getInstantiatedSymbol(); ISymbol instance = ((TemplateInstance)parent).getInstantiatedSymbol();
if( instance instanceof IContainerSymbol ) if( instance instanceof IContainerSymbol )
lookupInContained( data, (IContainerSymbol)instance ); temp = lookupInContained( data, (IContainerSymbol)instance );
else else
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplate ); throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplate );
data.templateInstance = tempInstance; data.templateInstance = tempInstance;
} else if( parent instanceof IDerivableContainerSymbol ){ } else if( parent instanceof IDerivableContainerSymbol ){
lookupInContained( data, (IDerivableContainerSymbol) parent ); temp = lookupInContained( data, (IDerivableContainerSymbol) parent );
} else { } else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo ); throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
} }
temp = resolveAmbiguities( data );
if( temp == null ){ if( temp.isEmpty() || data.mode == LookupMode.PREFIX ){
temp = lookupInParents( data, parent ); inherited = lookupInParents( data, parent );
mergeInheritedResults( temp, inherited );
} }
} else { } else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance ); throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance );
} }
} }
if( temp != null && temp.isType( data.type ) ){ if( temp != null && !temp.isEmpty() ){
if( symbol == null || symbol.isEmpty() ){
if( symbol == null ){
symbol = temp; symbol = temp;
} else if ( temp != null ) { } else if ( temp != null && !temp.isEmpty() ) {
//it is not ambiguous if temp & decl are the same thing and it is static Iterator iter = temp.keySet().iterator();
//or an enumerator Object key = null;
TypeInfo type = temp.getTypeInfo(); while( iter.hasNext() ){
key = iter.next();
if( symbol == temp && ( type.checkBit( TypeInfo.isStatic ) || type.isType( TypeInfo.t_enumerator ) ) ){ if( symbol.containsKey( key ) ){
temp = null; checkAmbiguity( symbol.get( key ), temp.get( key ) );
} else { } else {
throw( new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ) ); symbol.put( key, temp.get( key ) );
}
} }
} }
} else { } else {
temp = null; //reset temp for next iteration temp = null; //reset temp for next iteration
@ -440,6 +562,50 @@ public class ParserSymbolTable {
return symbol; 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 * function isValidOverload
* @param origDecl * @param origDecl
@ -561,119 +727,38 @@ public class ParserSymbolTable {
ISymbol obj = null; ISymbol obj = null;
IContainerSymbol cls = null; IContainerSymbol cls = null;
if( data.foundItems == null ){ if( data.foundItems == null || data.foundItems.isEmpty() || data.mode == LookupMode.PREFIX ){
return null; return null;
} }
int size = data.foundItems.size(); int size = data.foundItems.size();
Iterator iter = data.foundItems.iterator(); //Iterator iter = data.foundItems.iterator();
boolean needDecl = true; Object object = data.foundItems.get( data.name );
if( size == 0){ LinkedList functionList = new LinkedList();
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; if( object instanceof List ){
functionList.addAll( (List) object );
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();
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 );
} else { } 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.parameters = params;
data.forUserDefinedConversion = true; data.forUserDefinedConversion = true;
lookupInContained( data, (IContainerSymbol) sourceDecl ); data.foundItems = lookupInContained( data, (IContainerSymbol) sourceDecl );
conversion = (IParameterizedSymbol)resolveAmbiguities( data ); 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 static protected class LookupData
@ -2111,9 +2204,10 @@ public class ParserSymbolTable {
public boolean ignoreUsingDirectives = false; public boolean ignoreUsingDirectives = false;
public boolean forUserDefinedConversion = false; public boolean forUserDefinedConversion = false;
public HashSet foundItems = null; public Map foundItems = null;
public ISymbol templateInstance = null; public ISymbol templateInstance = null;
public LookupMode mode = LookupMode.NORMAL;
public LookupData( String n, TypeInfo.eType t, ISymbol i ){ public LookupData( String n, TypeInfo.eType t, ISymbol i ){
name = n; name = n;