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
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.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 ) );
}
}

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,
//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)
*/

View file

@ -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() );

View file

@ -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;

View file

@ -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 );
map = 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 );
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,7 +274,8 @@ 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;
@ -246,78 +288,63 @@ public class ParserSymbolTable {
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 ){
//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 );
while( name != null ) {
if( nameMatches( data, name ) ){
obj = ( declarations != null ) ? declarations.get( name ) : null;
foundSomething = true;
obj = collectSymbol( data, obj );
if( obj != null )
found.put( name, obj );
}
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 ){
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 );
//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();
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 );
}
foundSomething = true;
}
name = null;
}
}
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 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 {
throw( new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous ) );
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,108 +727,34 @@ 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;
Object object = data.foundItems.get( data.name );
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 = new LinkedList();
LinkedList functionList = null;
for( int i = size; i > 0; i-- ){
//if we
if( needDecl ){
decl = (ISymbol) iter.next();
if( object instanceof List ){
functionList.addAll( (List) object );
} else {
needDecl = true;
}
if( decl.isType( TypeInfo.t_function ) ){
if( functionList == null){
functionList = new LinkedList();
}
functionList.add( decl );
ISymbol symbol = (ISymbol) object;
if( symbol.isType( TypeInfo.t_function ) ){
functionList.add( symbol );
} 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;
}
}
return symbol;
}
}
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){
if( functionList.size() == 1){
return (ISymbol) functionList.getFirst();
} else {
data.foundItems.addAll( functionList );
throw new ParserSymbolTableException( ParserSymbolTableException.r_UnableToResolveFunction );
}
} else {
@ -670,13 +762,6 @@ public class ParserSymbolTable {
}
}
if( ambiguous ){
throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
} else {
return cls;
}
}
static protected IParameterizedSymbol resolveFunction( LookupData data, List functions ) throws ParserSymbolTableException{
if( functions == null ){
return null;
@ -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;