1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 01:15:29 +02:00

Patch for Andrew Niefer:

Patch for the parser's symbol table.
-friends
-"this" pointer
-enumerators
-argument dependent lookup
-function parameters & function overloading
This commit is contained in:
Doug Schaefer 2003-03-23 14:00:00 +00:00
parent e92cfae068
commit c27351afc0
5 changed files with 1311 additions and 124 deletions

View file

@ -1,3 +1,11 @@
2003-03-20 Andrew Niefer
Parser Symbol Table updates for:
* friends
* "this" pointer
* enumerators
* Argument dependent lookup
* adding parameters to functions & function overloading
2003-03-19 John Camelon
Updated Parser method visibility to solidify external interface.
Solved and removed TODO's from Scanner implementation.

View file

@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.core.parser;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Iterator;
/**
* @author aniefer
@ -24,7 +25,7 @@ import java.util.Map;
* Window>Preferences>Java>Code Generation.
*/
public class Declaration {
public class Declaration implements Cloneable {
/**
* Constructor for Declaration.
@ -42,6 +43,40 @@ public class Declaration {
_object = obj;
}
/**
* clone
* @see java.lang.Object#clone()
*
* implement clone for the purposes of using declarations.
* int _typeInfo; //by assignment
* String _name; //by assignment
* Object _object; //null this out
* Declaration _typeDeclaration; //by assignment
* Declaration _containingScope; //by assignment
* LinkedList _parentScopes; //shallow copy
* LinkedList _usingDirectives; //shallow copy
* HashMap _containedDeclarations; //shallow copy
* int _depth; //by assignment
*/
public Object clone(){
Declaration copy = null;
try{
copy = (Declaration)super.clone();
}
catch ( CloneNotSupportedException e ){
//should not happen
return null;
}
copy._object = null;
copy._parentScopes = ( _parentScopes != null ) ? (LinkedList) _parentScopes.clone() : null;
copy._usingDirectives = ( _usingDirectives != null ) ? (LinkedList) _usingDirectives.clone() : null;
copy._containedDeclarations = ( _containedDeclarations != null ) ? (HashMap) _containedDeclarations.clone() : null;
copy._parameters = ( _parameters != null ) ? (LinkedList) _parameters.clone() : null;
return copy;
}
public static final int typeMask = 0x001f;
public static final int isAuto = 0x0020;
public static final int isRegister = 0x0040;
@ -112,7 +147,7 @@ public class Declaration {
public static final int t_class = 2;
public static final int t_struct = 3;
public static final int t_union = 4;
public static final int t_enum = 5;
public static final int t_enumeration = 5;
public static final int t_function = 6;
public static final int t_char = 7;
public static final int t_wchar_t = 8;
@ -169,13 +204,6 @@ public class Declaration {
}
public void setTypeDeclaration( Declaration type ){
//setting our type to a declaration implies we are type t_type
try {
setType( t_type );
} catch (ParserSymbolTableException e) {
/*will never happen*/
}
_typeDeclaration = type;
}
@ -217,6 +245,93 @@ public class Declaration {
return _parentScopes;
}
public boolean needsDefinition(){
return _needsDefinition;
}
public void setNeedsDefinition( boolean need ) {
_needsDefinition = need;
}
public String getCVQualifier(){
return _cvQualifier;
}
public void setCVQualifier( String cv ){
_cvQualifier = cv;
}
public String getPtrOperator(){
return _ptrOperator;
}
public void setPtrOperator( String ptrOp ){
_ptrOperator = ptrOp;
}
public int getReturnType(){
return _returnType;
}
public void setReturnType( int type ){
_returnType = type;
}
public void addParameter( Declaration typeDecl, String ptrOperator, boolean hasDefault ){
if( _parameters == null ){
_parameters = new LinkedList();
}
ParameterInfo info = new ParameterInfo();
info.typeInfo = t_type;
info.typeDeclaration = typeDecl;
info.ptrOperator = ptrOperator;
info.hasDefaultValue = hasDefault;
_parameters.add( info );
}
public void addParameter( int type, String ptrOperator, boolean hasDefault ){
if( _parameters == null ){
_parameters = new LinkedList();
}
ParameterInfo info = new ParameterInfo();
info.typeInfo = type;
info.typeDeclaration = null;
info.ptrOperator = ptrOperator;
info.hasDefaultValue = hasDefault;
_parameters.add( info );
}
public boolean hasSameParameters( Declaration function ){
if( function.getType() != getType() ){
return false;
}
int size = _parameters.size();
if( function._parameters.size() != size ){
return false;
}
Iterator iter = _parameters.iterator();
Iterator fIter = function._parameters.iterator();
ParameterInfo info = null;
ParameterInfo fInfo = null;
for( int i = size; i > 0; i-- ){
info = (ParameterInfo) iter.next();
fInfo = (ParameterInfo) fIter.next();
if( !info.equals( fInfo ) ){
return false;
}
}
return true;
}
// Convenience methods
private void setBit(boolean b, int mask){
if( b ){
@ -234,11 +349,16 @@ public class Declaration {
private String _name; //our name
private Object _object; //the object associated with us
private Declaration _typeDeclaration; //our type if _typeInfo says t_type
private boolean _needsDefinition; //this name still needs to be defined
private String _cvQualifier;
private String _ptrOperator;
protected Declaration _containingScope; //the scope that contains us
protected LinkedList _parentScopes; //inherited scopes (is base classes)
protected LinkedList _usingDirectives; //collection of nominated namespaces
protected Map _containedDeclarations; //declarations contained by us.
protected HashMap _containedDeclarations; //declarations contained by us.
protected LinkedList _parameters; //parameter list
protected int _returnType;
protected int _depth; //how far down the scope stack we are
@ -253,4 +373,26 @@ public class Declaration {
public Declaration parent = null;
}
public class ParameterInfo
{
public ParameterInfo() {}
public ParameterInfo( int t, Declaration decl, String ptr, boolean def ){
typeInfo = t;
typeDeclaration = decl;
ptrOperator = ptr;
hasDefaultValue = def;
}
public boolean equals( ParameterInfo obj ){
return ( hasDefaultValue == obj.hasDefaultValue ) &&
( typeInfo == obj.typeInfo ) &&
( typeDeclaration == obj.typeDeclaration ) &&
( ptrOperator.equals( obj.ptrOperator ) );
}
public boolean hasDefaultValue;
public int typeInfo;
public Declaration typeDeclaration;
public String ptrOperator;
}
}

View file

@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
@ -38,6 +39,12 @@ public class ParserSymbolTable {
public ParserSymbolTable() {
super();
_compilationUnit = new Declaration();
try{
_compilationUnit.setType( Declaration.t_namespace );
} catch ( ParserSymbolTableException e ){
/*shouldn't happen*/
}
push( _compilationUnit );
}
@ -86,8 +93,7 @@ public class ParserSymbolTable {
return LookupNestedNameSpecifier( name, (Declaration) _contextStack.peek() );
}
private Declaration LookupNestedNameSpecifier(String name, Declaration inDeclaration ) throws ParserSymbolTableException
{
private Declaration LookupNestedNameSpecifier(String name, Declaration inDeclaration ) throws ParserSymbolTableException{
Declaration foundDeclaration = null;
LookupData data = new LookupData( name, Declaration.t_namespace );
@ -102,26 +108,203 @@ public class ParserSymbolTable {
return foundDeclaration;
}
/**
* LookupMemberForDefinition
* @param name
* @return Declaration
* @throws ParserSymbolTableException
*
* In a definition for a namespace member in which the declarator-id is a
* qualified-id, given that the qualified-id for the namespace member has
* the form "nested-name-specifier unqualified-id", the unqualified-id shall
* name a member of the namespace designated by the nested-name-specifier.
*
* ie:
* you have this:
* namespace A{
* namespace B{
* void f1(int);
* }
* using namespace B;
* }
*
* if you then do this
* void A::f1(int) { ... } //ill-formed, f1 is not a member of A
* but, you can do this (Assuming f1 has been defined elsewhere)
* A::f1( 1 ); //ok, finds B::f1
*
* ie, We need a seperate lookup function for looking up the member names
* for a definition.
*/
public Declaration LookupMemberForDefinition( String name ) throws ParserSymbolTableException{
LookupData data = new LookupData( name, -1 );
data.qualified = true;
return LookupInContained( data, (Declaration) _contextStack.peek() );
}
/**
*
* @param name
* @return Declaration
* @throws ParserSymbolTableException
*
* During lookup for a name preceding the :: scope resolution operator,
* object, function, and enumerator names are ignored.
*/
public Declaration QualifiedLookup( String name ) throws ParserSymbolTableException
{
public Declaration QualifiedLookup( String name ) throws ParserSymbolTableException{
LookupData data = new LookupData( name, -1 );
data.qualified = true;
return Lookup( data, (Declaration) _contextStack.peek() );
}
public void addUsingDirective( Declaration namespace ) throws ParserSymbolTableException
{
/**
*
* @param name
* @param parameters
* @return Declaration
* @throws ParserSymbolTableException
*/
public Declaration QualifiedFunctionLookup( String name, LinkedList parameters ) throws ParserSymbolTableException{
LookupData data = new LookupData( name, Declaration.t_function );
data.qualified = true;
data.parameters = parameters;
return Lookup( data, (Declaration) _contextStack.peek() );
}
/**
* MemberFunctionLookup
* @param name
* @param parameters
* @return Declaration
* @throws ParserSymbolTableException
*
* Member lookup really proceeds as an unqualified lookup, but doesn't
* include argument dependant scopes
*/
public Declaration MemberFunctionLookup( String name, LinkedList parameters ) throws ParserSymbolTableException{
LookupData data = new LookupData( name, Declaration.t_function );
data.parameters = parameters;
return Lookup( data, (Declaration) _contextStack.peek() );
}
/**
* UnqualifiedFunctionLookup
* @param name
* @param parameters
* @return Declaration
* @throws ParserSymbolTableException
*
* 3.4.2-1 When an unqualified name is used as the post-fix expression in a
* function call, other namespaces not consdiered during the usual
* unqualified lookup may be searched.
*
* 3.4.2-2 For each argument type T in the function call, there is a set of
* zero or more associated namespaces and a set of zero or more associated
* classes to be considered.
*
* If the ordinary unqualified lookup of the name find the declaration of a
* class member function, the associated namespaces and classes are not
* considered. Otherwise, the set of declarations found by the lookup of
* the function name is the union of the set of declarations found using
* ordinary unqualified lookup and the set of declarations found in the
* namespaces and classes associated with the argument types.
*/
public Declaration UnqualifiedFunctionLookup( String name, LinkedList parameters ) throws ParserSymbolTableException{
//figure out the set of associated scopes first, so we can remove those that are searched
//during the normal lookup to avoid doing them twice
HashSet associated = new HashSet();
//collect associated namespaces & classes.
int size = parameters.size();
Iterator iter = parameters.iterator();
Declaration.ParameterInfo param = null;
for( int i = size; i > 0; i-- ){
param = (Declaration.ParameterInfo) iter.next();
getAssociatedScopes( param.typeDeclaration, associated );
//if T is a pointer to a data member of class X, its associated namespaces and classes
//are those associated with the member type together with those associated with X
if( param.ptrOperator != null &&
(param.ptrOperator.equals("*") || param.ptrOperator.equals("[]")) &&
param.typeDeclaration._containingScope.isType( Declaration.t_class, Declaration.t_union ) )
{
getAssociatedScopes( param.typeDeclaration._containingScope, associated );
}
}
LookupData data = new LookupData( name, Declaration.t_function );
data.parameters = parameters;
data.associated = associated;
Declaration found = Lookup( data, (Declaration) _contextStack.peek() );
//if we haven't found anything, or what we found is not a class member, consider the
//associated scopes
if( found == null || found._containingScope.getType() != Declaration.t_class ){
LinkedList foundList = new LinkedList();
if( found != null ){
foundList.add( found );
}
iter = associated.iterator();
Declaration decl;
Declaration temp;
//use while hasNext instead of forloop since the lookup might remove
//items from the collection.
//Actually, I think that there will be no removals, but leave it like this anyway
while( iter.hasNext() ){
decl = (Declaration) iter.next();
data.qualified = true;
data.ignoreUsingDirectives = true;
temp = Lookup( data, decl );
if( temp != null ){
foundList.add( temp );
}
}
found = ResolveAmbiguities( data, foundList );
}
return found;
}
/**
* LookupForFriendship
* @param name
* @return Declaration
* 7.3.1.2-3 When looking for a prior declaration of a class or a function
* declared as a friend, scopes outside the innermost enclosing namespace
* scope are not considered.
* 11.4-9 If a friend declaration appears in a local class and the name
* specified is an unqualified name, a prior declaration is looked up
* without considering scopes that are outside the innermost enclosing non-
* class scope.
*/
private Declaration LookupForFriendship( String name ) throws ParserSymbolTableException{
LookupData data = new LookupData( name, -1 );
Declaration decl = (Declaration) _contextStack.peek();
boolean inClass = (decl.getType() == Declaration.t_class);
Declaration enclosing = decl._containingScope;
while( enclosing != null && (inClass ? enclosing.getType() != Declaration.t_class
: enclosing.getType() == Declaration.t_namespace) )
{
enclosing = enclosing._containingScope;
}
data.stopAt = enclosing;
return Lookup( data, (Declaration) _contextStack.peek() );
}
public void addUsingDirective( Declaration namespace ) throws ParserSymbolTableException{
if( namespace.getType() != Declaration.t_namespace ){
throw new ParserSymbolTableException();
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
}
Declaration declaration = (Declaration) _contextStack.peek();
@ -133,10 +316,77 @@ public class ParserSymbolTable {
declaration._usingDirectives.add( namespace );
}
/**
* addUsingDeclaration
* @param obj
* @throws ParserSymbolTableException
*
* 7.3.3-9 The entity declared by a using-declaration shall be known in the
* context using it according to its definition at the point of the using-
* declaration. Definitions added to the namespace after the using-
* declaration are not considered when a use of the name is made.
*
* 7.3.3-4 A using-declaration used as a member-declaration shall refer to a
* member of a base class of the class being defined, shall refer to a
* member of an anonymous union that is a member of a base class of the
* class being defined, or shall refer to an enumerator for an enumeration
* type that is a member of a base class of the class being defined.
*/
public Declaration addUsingDeclaration( Declaration obj ) throws ParserSymbolTableException{
Declaration clone = null;
Declaration context = (Declaration) _contextStack.peek();
boolean okToAdd = false;
//7.3.3-4
if( context.isType( Declaration.t_class, Declaration.t_union ) ){
//a member of a base class
if( obj.getContainingScope().getType() == context.getType() ){
okToAdd = hasBaseClass( context, obj.getContainingScope() );
}
//TBD : a member of an _anonymous_ union
else if ( obj.getContainingScope().getType() == Declaration.t_union ) {
Declaration union = obj.getContainingScope();
okToAdd = hasBaseClass( context, union.getContainingScope() );
}
//an enumerator for an enumeration
else if ( obj.getType() == Declaration.t_enumerator ){
Declaration enumeration = obj.getContainingScope();
okToAdd = hasBaseClass( context, enumeration.getContainingScope() );
}
} else {
okToAdd = true;
}
if( okToAdd ){
clone = (Declaration) obj.clone(); //7.3.3-9
addDeclaration( clone );
} else {
throw new ParserSymbolTableException();
}
return clone;
}
public void addDeclaration( Declaration obj ) throws ParserSymbolTableException{
Declaration containing = (Declaration) _contextStack.peek();
//handle enumerators
if( obj.getType() == Declaration.t_enumerator ){
//a using declaration of an enumerator will not be contained in a
//enumeration.
if( containing.getType() == Declaration.t_enumeration ){
//Following the closing brace of an enum-specifier, each enumerator has the type of its
//enumeration
obj.setTypeDeclaration( containing );
//Each enumerator is declared in the scope that immediately contains the enum-specifier
containing = containing.getContainingScope();
}
}
Map declarations = containing.getContainedDeclarations();
boolean unnamed = obj.getName().equals( "" );
Object origObj = null;
obj.setContainingScope( containing );
@ -161,7 +411,7 @@ public class ParserSymbolTable {
throw new ParserSymbolTableException();
}
if( (origList == null) ? isValidOverload( origDecl, obj ) : isValidOverload( origList, obj ) ){
if( unnamed || (origList == null) ? isValidOverload( origDecl, obj ) : isValidOverload( origList, obj ) ){
if( origList == null ){
origList = new LinkedList();
origList.add( origDecl );
@ -174,11 +424,84 @@ public class ParserSymbolTable {
//origList is already in _containedDeclarations
}
} else {
throw new ParserSymbolTableException();
throw new ParserSymbolTableException( ParserSymbolTableException.r_InvalidOverload );
}
} else {
declarations.put( obj.getName(), obj );
}
//take care of the this pointer
if( obj.getType() == Declaration.t_function && !obj.isStatic() ){
addThis( obj );
}
}
/**
*
* @param name
* @return Declaration
* @throws ParserSymbolTableException
*
* 7.3.1.2-3 If a friend declaration in a non-local class first declares a
* class or function, the friend class or function is a member of the
* innermost enclosing namespace.
*
* TBD: if/when the parser symbol table starts caring about visibility
* (public/protected/private) we will need to do more to record friendship.
*/
public Declaration addFriend( String name ) throws ParserSymbolTableException{
Declaration friend = LookupForFriendship( name );
if( friend == null ){
friend = new Declaration( name );
friend.setNeedsDefinition( true );
Declaration decl = (Declaration) _contextStack.peek();
Declaration containing = decl._containingScope;
//find innermost enclosing namespace
while( containing != null && containing.getType() != Declaration.t_namespace ){
containing = containing._containingScope;
}
Declaration namespace = (containing == null ) ? _compilationUnit : containing;
push( namespace );
addDeclaration( friend );
pop();
}
return friend;
}
/**
*
* @param obj
* @throws ParserSymbolTableException
* 9.3.2-1 In the body of a nonstatic member function... the type of this of
* a class X is X*. If the member function is declared const, the type of
* this is const X*, if the member function is declared volatile, the type
* of this is volatile X*....
*/
private void addThis( Declaration obj ) throws ParserSymbolTableException{
if( obj.getType() != Declaration.t_function || obj.isStatic() ){
return;
}
if( obj._containingScope.isType( Declaration.t_class, Declaration.t_union ) ){
//check to see if there is already a this object, since using declarations
//of function will have them from the original declaration
LookupData data = new LookupData( "this", -1 );
if( LookupInContained( data, obj ) == null ){
Declaration thisObj = new Declaration("this");
thisObj.setType( Declaration.t_type );
thisObj.setTypeDeclaration( obj._containingScope );
thisObj.setCVQualifier( obj.getCVQualifier() );
thisObj.setPtrOperator("*");
push( obj );
addDeclaration( thisObj );
pop();
}
}
}
/**
@ -206,43 +529,45 @@ public class ParserSymbolTable {
foundNames.add( decl );
}
//check nominated namespaces
//the transitives list is populated in LookupInNominated, and then
//processed in ProcessDirectives
data.visited.clear(); //each namesapce is searched at most once, so keep track
tempList = LookupInNominated( data, inDeclaration, transitives );
if( tempList != null ){
foundNames.addAll( tempList );
}
if( !data.ignoreUsingDirectives ){
//check nominated namespaces
//the transitives list is populated in LookupInNominated, and then
//processed in ProcessDirectives
//if we are doing a qualified lookup, only process using directives if
//we haven't found the name yet.
if( !data.qualified || foundNames.size() == 0 ){
ProcessDirectives( inDeclaration, data, transitives );
data.visited.clear(); //each namesapce is searched at most once, so keep track
if( inDeclaration._usingDirectives != null ){
ProcessDirectives( inDeclaration, data, inDeclaration._usingDirectives );
tempList = LookupInNominated( data, inDeclaration, transitives );
if( tempList != null ){
foundNames.addAll( tempList );
}
while( data.usingDirectives != null && data.usingDirectives.get( inDeclaration ) != null ){
transitives.clear();
tempList = LookupInNominated( data, inDeclaration, transitives );
//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 || foundNames.size() == 0 ){
ProcessDirectives( inDeclaration, data, transitives );
if( tempList != null ){
foundNames.addAll( tempList );
if( inDeclaration._usingDirectives != null ){
ProcessDirectives( inDeclaration, data, inDeclaration._usingDirectives );
}
if( !data.qualified || foundNames.size() == 0 ){
ProcessDirectives( inDeclaration, data, transitives );
while( data.usingDirectives != null && data.usingDirectives.get( inDeclaration ) != null ){
transitives.clear();
tempList = LookupInNominated( data, inDeclaration, transitives );
if( tempList != null ){
foundNames.addAll( tempList );
}
if( !data.qualified || foundNames.size() == 0 ){
ProcessDirectives( inDeclaration, data, transitives );
}
}
}
}
decl = ResolveAmbiguities( foundNames );
decl = ResolveAmbiguities( data, foundNames );
if( decl != null ){
return decl;
}
@ -343,6 +668,11 @@ public class ParserSymbolTable {
Declaration temp = null;
Object obj = null;
if( data.associated != null ){
//we are looking in lookIn, remove it from the associated scopes list
data.associated.remove( lookIn );
}
Map declarations = lookIn.getContainedDeclarations();
if( declarations == null )
return null;
@ -353,7 +683,7 @@ public class ParserSymbolTable {
//not found
return null;
}
//the contained declarations map either to a Declaration object, or to a list
//of declaration objects.
if( obj.getClass() == Declaration.class ){
@ -381,7 +711,7 @@ public class ParserSymbolTable {
if( found == null || found.size() == 0 )
return null;
return ResolveAmbiguities( found );
return ResolveAmbiguities( data, found );
}
/**
@ -393,14 +723,21 @@ public class ParserSymbolTable {
*/
private static Declaration LookupInParents( LookupData data, Declaration lookIn ) throws ParserSymbolTableException{
LinkedList scopes = lookIn.getParentScopes();
Declaration decl = null;
Declaration temp = null;
Declaration decl = null;
Iterator iterator = null;
Declaration.ParentWrapper wrapper = null;
if( scopes == null )
return null;
//use data to detect circular inheritance
if( data.inheritanceChain == null )
data.inheritanceChain = new HashSet();
data.inheritanceChain.add( lookIn );
iterator = scopes.iterator();
int size = scopes.size();
@ -413,15 +750,27 @@ public class ParserSymbolTable {
data.visited.add( wrapper.parent );
}
//is this name define in this scope?
temp = LookupInContained( data, wrapper.parent );
//HashSet.add returns false if wrapper.parent is already in the set
//this means we have circular inheritance
if( data.inheritanceChain.add( wrapper.parent ) ){
//is this name define in this scope?
temp = LookupInContained( data, wrapper.parent );
if( temp == null ){
temp = LookupInParents( data, wrapper.parent );
if( temp == null ){
temp = LookupInParents( data, wrapper.parent );
}
data.inheritanceChain.remove( wrapper.parent );
} else {
throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance );
}
}
if( temp != null && temp.isType( data.type ) ){
if( decl == null ){
decl = temp;
} else if ( temp != null ) {
@ -458,18 +807,14 @@ public class ParserSymbolTable {
int origType = origDecl.getType();
int newType = newDecl.getType();
if( (origType >= Declaration.t_class && origType <= Declaration.t_enum) && //class name or enumeration ...
if( (origType >= Declaration.t_class && origType <= Declaration.t_enumeration) && //class name or enumeration ...
( newType == Declaration.t_type || (newType >= Declaration.t_function && newType <= Declaration.typeMask) ) ){
return true;
}
//if the origtype is not a class-name or enumeration name, then the only other
//allowable thing is if they are both functions.
else if( origType == Declaration.t_function && newType == Declaration.t_function ){
return true;
}
return false;
return isValidFunctionOverload( origDecl, newDecl );
}
private static boolean isValidOverload( LinkedList origList, Declaration newDecl ){
@ -486,12 +831,12 @@ public class ParserSymbolTable {
Iterator iter = origList.iterator();
Declaration decl = (Declaration) iter.next();
boolean valid = (( decl.getType() >= Declaration.t_class && decl.getType() <= Declaration.t_enum ) ||
decl.getType() == Declaration.t_function );
boolean valid = (( decl.getType() >= Declaration.t_class && decl.getType() <= Declaration.t_enumeration ) ||
isValidFunctionOverload( decl, newDecl ));
while( valid && iter.hasNext() ){
decl = (Declaration) iter.next();
valid = ( decl.getType() == Declaration.t_function );
valid = isValidFunctionOverload( decl, newDecl );
}
return valid;
@ -501,7 +846,31 @@ public class ParserSymbolTable {
return true;
}
static private Declaration ResolveAmbiguities( LinkedList items ) throws ParserSymbolTableException{
private static boolean isValidFunctionOverload( Declaration origDecl, Declaration newDecl ){
if( origDecl.getType() != Declaration.t_function || newDecl.getType() != Declaration.t_function ){
return false;
}
if( origDecl.hasSameParameters( newDecl ) ){
//functions with the same name and same parameter types cannot be overloaded if any of them
//is static
if( origDecl.isStatic() || newDecl.isStatic() ){
return false;
}
//if none of them are static, then the function can be overloaded if they differ in the type
//of their implicit object parameter.
if( origDecl.getCVQualifier() != newDecl.getCVQualifier() ){
return true;
}
return false;
}
return true;
}
static private Declaration ResolveAmbiguities( LookupData data, LinkedList items ) throws ParserSymbolTableException{
Declaration decl = null;
int size = items.size();
@ -514,8 +883,8 @@ public class ParserSymbolTable {
Declaration first = (Declaration)items.removeFirst();
//if first one is a class-name, the next ones hide it
if( first.getType() >= Declaration.t_class && first.getType() <= Declaration.t_enum ){
return ResolveAmbiguities( items );
if( first.getType() >= Declaration.t_class && first.getType() <= Declaration.t_enumeration ){
return ResolveAmbiguities( data, items );
}
//else, if the first is an object (ie not a function), the rest must be the same
@ -529,11 +898,11 @@ public class ParserSymbolTable {
if( needSame ){
if( decl != first ){
throw new ParserSymbolTableException();
throw new ParserSymbolTableException( ParserSymbolTableException.r_AmbiguousName );
}
} else {
if( decl.getType() != Declaration.t_function ){
throw new ParserSymbolTableException();
throw new ParserSymbolTableException( ParserSymbolTableException.r_AmbiguousName );
}
}
}
@ -542,16 +911,63 @@ public class ParserSymbolTable {
return first;
} else {
items.addFirst( first );
return ResolveFunction( items );
return ResolveFunction( data, items );
}
}
}
static private Declaration ResolveFunction( LinkedList functions ){
//TBD
static private Declaration ResolveFunction( LookupData data, LinkedList functions ){
int numParameters = ( data.parameters == null ) ? 0 : data.parameters.size();
int num;
//Trim the list down to the set of viable functions
Declaration function;
Iterator iter = functions.iterator();
while( iter.hasNext() ){
function = (Declaration) iter.next();
num = ( function._parameters == null ) ? 0 : function._parameters.size();
//if there are m arguments in the list, all candidate functions having m parameters
//are viable
if( num == numParameters ){
continue;
}
//A candidate function having fewer than m parameters is viable only if it has an
//ellipsis in its parameter list.
else if( num < numParameters ) {
//TBD ellipsis
//not enough parameters, remove it
iter.remove();
}
//a candidate function having more than m parameters is viable only if the (m+1)-st
//parameter has a default argument
else {
ListIterator listIter = function._parameters.listIterator( num - 1 );
Declaration.ParameterInfo param;
for( int i = num; i > ( numParameters - num ); i-- ){
param = (Declaration.ParameterInfo)listIter.previous();
if( !param.hasDefaultValue ){
iter.remove();
break;
}
}
}
}
//TBD, rank implicit conversion sequences to determine which one is best.
int size = functions.size();
if( size == 0 ){
return null;
}
else if( size == 1) {
return (Declaration) functions.getFirst();
}
return null;
}
/**
* function ProcessDirectives
* @param Declaration decl
@ -624,18 +1040,99 @@ public class ParserSymbolTable {
}
}
/**
*
* @param obj
* @param base
* @return boolean
* figure out if base is a base class of obj.
*
* TBD: Consider rewriting iteratively for performance.
*/
static private boolean hasBaseClass( Declaration obj, Declaration base ){
boolean isABaseClass = false;
if( obj._parentScopes != null ){
Declaration decl;
Declaration.ParentWrapper wrapper;
Iterator iter = obj._parentScopes.iterator();
int size = obj._parentScopes.size();
for( int i = size; i > 0; i-- ){
wrapper = (Declaration.ParentWrapper) iter.next();
decl = wrapper.parent;
if( decl == base || hasBaseClass( decl, base ) ){
return true;
}
}
}
return false;
}
static private void getAssociatedScopes( Declaration decl, HashSet associated ){
if( decl == null ){
return;
}
//if T is a class type, its associated classes are the class itself,
//and its direct and indirect base classes. its associated Namespaces are the
//namespaces in which its associated classes are defined
if( decl.getType() == Declaration.t_class ){
associated.add( decl );
getBaseClassesAndContainingNamespaces( decl, associated );
}
//if T is a union or enumeration type, its associated namespace is the namespace in
//which it is defined. if it is a class member, its associated class is the member's
//class
else if( decl.getType() == Declaration.t_union || decl.getType() == Declaration.t_enumeration ){
associated.add( decl._containingScope );
}
}
static private void getBaseClassesAndContainingNamespaces( Declaration obj, HashSet classes ){
if( obj._parentScopes != null ){
if( classes == null ){
return;
}
Iterator iter = obj._parentScopes.iterator();
int size = obj._parentScopes.size();
Declaration base;
for( int i = size; i > 0; i-- ){
base = (Declaration) iter.next();
classes.add( base );
if( base._containingScope.getType() == Declaration.t_namespace ){
classes.add( base._containingScope );
}
getBaseClassesAndContainingNamespaces( base, classes );
}
}
}
private Stack _contextStack = new Stack();
private Declaration _compilationUnit;
private class LookupData
{
public String name;
public Map usingDirectives;
public Set visited = new HashSet(); //used to ensure we don't visit things more than once
public HashSet inheritanceChain; //used to detect circular inheritance
public LinkedList parameters; //parameter info for resolving functions
public HashSet associated; //associated namespaces for argument dependant lookup
public Declaration stopAt; //stop looking along the stack once we hit this declaration
public int type = -1;
public int upperType = 0;
public boolean qualified = false;
public boolean ignoreUsingDirectives = false;
public LookupData( String n, int t ){
name = n;

View file

@ -36,9 +36,11 @@ public class ParserSymbolTableException extends Exception {
reason = r;
}
public static final int r_Unspecified = -1;
public static final int r_AmbiguousName = 0;
public static final int r_BadTypeInfo = 1;
public static final int r_Unspecified = -1;
public static final int r_AmbiguousName = 0;
public static final int r_BadTypeInfo = 1;
public static final int r_CircularInheritance = 2;
public static final int r_InvalidOverload = 3;
public int reason = -1;
}

View file

@ -12,6 +12,7 @@
package org.eclipse.cdt.core.parser.tests;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import junit.framework.TestCase;
@ -243,6 +244,33 @@ public class ParserSymbolTableTest extends TestCase {
}
/**
*
* @throws Exception
* test for circular inheritance
*/
public void testCircularParentLookup() throws Exception{
newTable();
Declaration a = new Declaration("a");
table.addDeclaration( a );
Declaration b = new Declaration("b");
table.addDeclaration(b);
a.addParent( b );
b.addParent( a );
table.push( a );
try{
Declaration look = table.Lookup("foo");
assertTrue( false );
} catch ( ParserSymbolTableException e) {
assertEquals( e.reason, ParserSymbolTableException.r_CircularInheritance );
}
}
/**
* testVirtualParentLookup
*
@ -320,7 +348,7 @@ public class ParserSymbolTableTest extends TestCase {
assertTrue( false );
}
catch( ParserSymbolTableException e){
assertTrue( true );
assertEquals( e.reason, ParserSymbolTableException.r_AmbiguousName );
}
}
@ -351,7 +379,10 @@ public class ParserSymbolTableTest extends TestCase {
table.addDeclaration( d );
Declaration enum = new Declaration("enum");
enum.setType( Declaration.t_enumerator );
enum.setType( Declaration.t_enumeration );
Declaration enumerator = new Declaration( "enumerator" );
enumerator.setType( Declaration.t_enumerator );
Declaration stat = new Declaration("static");
stat.setStatic(true);
@ -360,6 +391,9 @@ public class ParserSymbolTableTest extends TestCase {
table.push(d);
table.addDeclaration( enum );
table.push( enum );
table.addDeclaration( enumerator );
table.pop();
table.addDeclaration( stat );
table.addDeclaration( x );
table.pop();
@ -371,7 +405,7 @@ public class ParserSymbolTableTest extends TestCase {
table.push( a );
try{
table.Lookup( "enum" );
table.Lookup( "enumerator" );
assertTrue( true );
}
catch ( ParserSymbolTableException e){
@ -391,7 +425,7 @@ public class ParserSymbolTableTest extends TestCase {
assertTrue( false );
}
catch ( ParserSymbolTableException e){
assertTrue( true );
assertEquals( e.reason, ParserSymbolTableException.r_AmbiguousName );
}
}
@ -476,46 +510,6 @@ public class ParserSymbolTableTest extends TestCase {
assertEquals( look, member );
}
/**
* testFunctions
* @throws Exception
* Functions are stored by signature. Where the signature can really be of
* any for you like, as long as it can't possibly be a regular name (ie
* including the parenthese is good...)
* So lookup of function names proceeds inthe same manner as normal names,
* this test doesn't really test anything new
*/
public void testFunctions() throws Exception{
newTable();
Declaration cls = new Declaration( "class");
Declaration f1 = new Declaration("foo()");
Declaration f2 = new Declaration("foo(int)");
Declaration f3 = new Declaration("foo(int,char)");
table.addDeclaration(cls);
table.push(cls);
table.addDeclaration( f1 );
table.addDeclaration( f2 );
table.addDeclaration( f3 );
//return type can be specified by setting the TypeDeclaration
Declaration returnType = new Declaration("return");
f1.setTypeDeclaration( returnType );
f2.setTypeDeclaration( returnType );
f3.setTypeDeclaration( returnType );
assertEquals( table.Lookup("foo()"), f1 );
assertEquals( table.Lookup("foo(int)"), f2 );
assertEquals( table.Lookup("foo(int,char)"), f3 );
//notice that, with the current implementation, you can't do a lookup
//on just the function name without the rest of the signature
assertEquals( table.Lookup("foo"), null );
}
/**
*
* @throws Exception
@ -649,7 +643,8 @@ public class ParserSymbolTableTest extends TestCase {
}
catch ( ParserSymbolTableException e )
{
assertTrue(true); //ambiguous B::C::i and A::i
//ambiguous B::C::i and A::i
assertEquals( e.reason, ParserSymbolTableException.r_AmbiguousName );
}
table.pop(); //end f2
table.pop(); //end nsD
@ -732,7 +727,8 @@ public class ParserSymbolTableTest extends TestCase {
}
catch ( ParserSymbolTableException e )
{
assertTrue( true ); //ambiguous, both M::i and N::i are visible.
//ambiguous, both M::i and N::i are visible.
assertEquals( e.reason, ParserSymbolTableException.r_AmbiguousName );
}
look = table.LookupNestedNameSpecifier("N");
@ -1025,9 +1021,551 @@ public class ParserSymbolTableTest extends TestCase {
try{
look = table.QualifiedLookup( "y" );
assertTrue(false);
} catch ( Exception e ) {
assertTrue(true);
} catch ( ParserSymbolTableException e ) {
assertEquals( e.reason, ParserSymbolTableException.r_AmbiguousName );
}
}
/**
* In a definition for a namespace member in which the declarator-id is a
* qualified-id, given that the qualified-id for the namespace member has
* the form "nested-name-specifier unqualified-id", the unqualified-id shall
* name a member of the namespace designated by the nested-name-specifier.
*
* namespace A{
* namespace B{
* void f1(int);
* }
* using namespace B;
* }
* void A::f1(int) { ... } //ill-formed, f1 is not a member of A
*/
public void testLookupMemberForDefinition() throws Exception{
newTable();
Declaration nsA = new Declaration( "A" );
nsA.setType( Declaration.t_namespace );
table.addDeclaration( nsA );
table.push( nsA );
Declaration nsB = new Declaration( "B" );
nsB.setType( Declaration.t_namespace );
table.addDeclaration( nsB );
table.push( nsB );
Declaration f1 = new Declaration("f1");
f1.setType( Declaration.t_function );
table.addDeclaration( f1 );
table.pop();
table.addUsingDirective( nsB );
table.pop();
Declaration look = table.LookupNestedNameSpecifier( "A" );
assertEquals( nsA, look );
table.push( look );
look = table.LookupMemberForDefinition( "f1" );
assertEquals( look, null );
//but notice if you wanted to do A::f1 as a function call, it is ok
look = table.QualifiedLookup( "f1" );
assertEquals( look, f1 );
}
/**
* testUsingDeclaration
* @throws Exception
* 7.3.3-4 A using-declaration used as a member-declaration shall refer to a
* member of a base-class of the class being defined, shall refer to a
* member of an anonymous union that is a member of a base class of the
* class being defined or shall refer to an enumerator for an enumeration
* type that is a member of a base class of the class being defined
*
* struct B {
* void f( char );
* enum E { e };
* union { int x; };
* };
* class C {
* int g();
* }
* struct D : B {
* using B::f; //ok, B is a base class of D
* using B::e; //ok, e is an enumerator in base class B
* using B::x; //ok, x is an union member of base class B
* using C::g; //error, C isn't a base class of D
* }
*/
public void testUsingDeclaration() throws Exception{
newTable();
Declaration B = new Declaration("B");
B.setType( Declaration.t_struct );
table.addDeclaration( B );
table.push( B );
Declaration f = new Declaration("f");
f.setType( Declaration.t_function );
table.addDeclaration( f );
Declaration E = new Declaration( "E" );
E.setType( Declaration.t_enumeration );
table.addDeclaration( E );
table.push( E );
Declaration e = new Declaration( "e" );
e.setType( Declaration.t_enumerator );
table.addDeclaration( e );
table.pop();
//TBD: Anonymous unions are not yet implemented
table.pop();
Declaration C = new Declaration( "C" );
C.setType( Declaration.t_class );
table.addDeclaration( C );
table.push( C );
Declaration g = new Declaration( "g" );
g.setType( Declaration.t_function );
table.addDeclaration( g );
table.pop();
Declaration D = new Declaration( "D" );
D.setType( Declaration.t_struct );
Declaration look = table.Lookup( "B" );
assertEquals( look, B );
D.addParent( look );
table.addDeclaration( D );
table.push( D );
Declaration lookB = table.LookupNestedNameSpecifier("B");
assertEquals( lookB, B );
table.push( lookB );
look = table.QualifiedLookup( "f" );
table.pop();
assertEquals( look, f );
table.addUsingDeclaration( look );
table.push( lookB );
look = table.QualifiedLookup( "e" );
table.pop();
assertEquals( look, e );
table.addUsingDeclaration( look );
//TBD anonymous union
//table.push( lookB );
//look = table.QualifiedLookup( "x")
//table.pop();
//table.addUsingDeclaration( look );
look = table.LookupNestedNameSpecifier("C");
assertEquals( look, C );
table.push( look );
look = table.QualifiedLookup("g");
table.pop();
assertEquals( look, g );
try{
table.addUsingDeclaration( look );
assertTrue( false );
}
catch ( ParserSymbolTableException exception ){
assertTrue( true );
}
}
/**
* testUsingDeclaration_2
* @throws Exception
* 7.3.3-9 The entity declared by a using-declaration shall be known in the
* context using it according to its definition at the point of the using-
* declaration. Definitions added to the namespace after the using-
* declaration are not considered when a use of the name is made.
*
* namespace A {
* void f(int);
* }
* using A::f;
*
* namespace A {
* void f(char);
* }
* void foo(){
* f('a'); //calls f( int )
* }
* void bar(){
* using A::f;
* f('a'); //calls f( char );
* }
*
* TBD: we need to support using declarations for overloaded functions.
* TBD: function overload resolution is not done yet, so the call to f in
* bar() can't be tested yet.
*/
public void testUsingDeclaration_2() throws Exception{
newTable();
Declaration A = new Declaration( "A" );
A.setType( Declaration.t_namespace );
table.addDeclaration( A );
table.push( A );
Declaration f1 = new Declaration( "f" );
f1.setType( Declaration.t_function );
f1.setReturnType( Declaration.t_void );
f1.addParameter( Declaration.t_int, "", false );
table.addDeclaration( f1 );
table.pop();
Declaration look = table.LookupNestedNameSpecifier("A");
assertEquals( look, A );
table.push( A );
look = table.QualifiedLookup("f");
assertEquals( look, f1 );
table.pop();
Declaration usingF = table.addUsingDeclaration( look );
look = table.Lookup("A");
assertEquals( look, A );
table.push( look );
Declaration f2 = new Declaration("f");
f2.setType( Declaration.t_function );
f2.setReturnType( Declaration.t_void );
f2.addParameter( Declaration.t_char, "", false );
table.addDeclaration( f2 );
table.pop();
Declaration foo = new Declaration("foo");
foo.setType( Declaration.t_function );
table.addDeclaration( foo );
table.push( foo );
LinkedList paramList = new LinkedList();
Declaration.ParameterInfo param = foo.new ParameterInfo();
param.typeInfo = Declaration.t_char;
paramList.add( param );
look = table.UnqualifiedFunctionLookup( "f", paramList );
assertEquals( look, usingF );
}
/**
* testThisPointer
* @throws Exception
* In the body of a nonstatic member function... the type of this of a class
* X is X*. If the member function is declared const, the type of this is
* const X*, if the member function is declared volatile, the type of this
* is volatile X*....
*/
public void testThisPointer() throws Exception{
newTable();
Declaration cls = new Declaration("class");
cls.setType( Declaration.t_class );
Declaration fn = new Declaration("function");
fn.setType( Declaration.t_function );
fn.setCVQualifier("const");
table.addDeclaration( cls );
table.push( cls );
table.addDeclaration( fn );
table.push( fn );
Declaration look = table.Lookup("this");
assertTrue( look != null );
assertEquals( look.getType(), Declaration.t_type );
assertEquals( look.getTypeDeclaration(), cls );
assertEquals( look.getPtrOperator(), "*" );
assertEquals( look.getCVQualifier(), fn.getCVQualifier() );
assertEquals( look.getContainingScope(), fn );
}
/**
* testEnumerator
* @throws Exception
* Following the closing brace of an enum-specifier, each enumerator has the
* type of its enumeration.
* The enum-name and each enumerator declared by an enum-specifier is
* declared in the scope that immediately contains the enum-specifier
*/
public void testEnumerator() throws Exception{
newTable();
Declaration cls = new Declaration("class");
cls.setType( Declaration.t_class );
Declaration enumeration = new Declaration("enumeration");
enumeration.setType( Declaration.t_enumeration );
table.addDeclaration( cls );
table.push( cls );
table.addDeclaration( enumeration );
table.push( enumeration );
Declaration enumerator = new Declaration( "enumerator" );
enumerator.setType( Declaration.t_enumerator );
table.addDeclaration( enumerator );
table.pop();
Declaration look = table.Lookup( "enumerator" );
assertEquals( look, enumerator );
assertEquals( look.getContainingScope(), cls );
assertEquals( look.getTypeDeclaration(), enumeration );
}
/**
*
* @throws Exception
*
* namespace NS{
* class T {};
* void f( T );
* }
* NS::T parm;
* int main(){
* f( parm ); //ok, calls NS::f
* }
*/
public void testArgumentDependentLookup() throws Exception{
newTable();
Declaration NS = new Declaration("NS");
NS.setType( Declaration.t_namespace );
table.addDeclaration( NS );
table.push( NS );
Declaration T = new Declaration("T");
T.setType( Declaration.t_class );
table.addDeclaration( T );
Declaration f = new Declaration("f");
f.setType( Declaration.t_function );
f.setReturnType( Declaration.t_void );
Declaration look = table.Lookup( "T" );
assertEquals( look, T );
f.addParameter( look, "", false );
table.addDeclaration( f );
table.pop(); //done NS
look = table.LookupNestedNameSpecifier( "NS" );
assertEquals( look, NS );
table.push( look );
look = table.QualifiedLookup( "T" );
assertEquals( look, T );
table.pop();
Declaration param = new Declaration("parm");
param.setType( Declaration.t_type );
param.setTypeDeclaration( look );
table.addDeclaration( param );
Declaration main = new Declaration("main");
main.setType( Declaration.t_function );
main.setReturnType( Declaration.t_int );
table.addDeclaration( main );
table.push( main );
LinkedList paramList = new LinkedList();
look = table.Lookup( "parm" );
assertEquals( look, param );
Declaration.ParameterInfo p = look.new ParameterInfo();
p.typeInfo = look.getType();
p.typeDeclaration = look.getTypeDeclaration();
paramList.add( p );
look = table.UnqualifiedFunctionLookup( "f", paramList );
assertEquals( look, f );
}
/**
* testArgumentDependentLookup_2
* @throws Exception
* in the following, NS2 is an associated namespace of class B which is an
* associated namespace of class A, so we should find f in NS2, we should
* not find f in NS1 because usings are ignored for associated scopes.
*
*
* namespace NS1{
* void f( void * ){};
* }
* namespace NS2{
* using namespace NS1;
* class B {};
* void f( void * ){};
* }
*
* class A : public NS2::B {};
*
* A a;
* f( &a );
*
*/
public void testArgumentDependentLookup_2() throws Exception{
newTable();
Declaration NS1 = new Declaration( "NS1" );
NS1.setType( Declaration.t_namespace );
table.addDeclaration( NS1 );
table.push( NS1 );
Declaration f1 = new Declaration( "f" );
f1.setType( Declaration.t_function );
f1.setReturnType( Declaration.t_void );
f1.addParameter( Declaration.t_void, "*", false );
table.addDeclaration( f1 );
table.pop();
Declaration NS2 = new Declaration( "NS2" );
NS2.setType( Declaration.t_namespace );
table.addDeclaration( NS2 );
table.push( NS2 );
Declaration look = table.Lookup( "NS1" );
assertEquals( look, NS1 );
table.addUsingDirective( look );
Declaration B = new Declaration( "B" );
B.setType( Declaration.t_class );
table.addDeclaration( B );
Declaration f2 = new Declaration( "f" );
f2.setType( Declaration.t_function );
f2.setReturnType( Declaration.t_void );
f2.addParameter( Declaration.t_void, "*", false );
table.addDeclaration( f2 );
table.pop();
Declaration A = new Declaration( "A" );
A.setType( Declaration.t_class );
look = table.LookupNestedNameSpecifier( "NS2" );
assertEquals( look, NS2 );
table.push( look );
look = table.QualifiedLookup( "B" );
assertEquals( look, B );
A.addParent( look );
table.addDeclaration( A );
look = table.Lookup( "A" );
assertEquals( look, A );
Declaration a = new Declaration( "a" );
a.setType( Declaration.t_type );
a.setTypeDeclaration( look );
table.addDeclaration( a );
LinkedList paramList = new LinkedList();
look = table.Lookup( "a" );
assertEquals( look, a );
Declaration.ParameterInfo param = look.new ParameterInfo( look.getType(), look, "&", false );
paramList.add( param );
look = table.UnqualifiedFunctionLookup( "f", paramList );
assertEquals( look, f2 );
}
/**
* testFunctionOverloading
* @throws Exception
* Note that this test has been contrived to not strain the resolution as
* that aspect is not yet complete.
*
* class C
* {
* void foo( int i );
* void foo( int i, char c );
* void foo( int i, char c, C * ptr );
* }
*
* C * c = new C;
* c->foo( 1 );
* c->foo( 1, 'a' );
* c->foo( 1, 'a', c );
*
*/
public void testFunctionOverloading() throws Exception{
newTable();
Declaration C = new Declaration( "C" );
table.addDeclaration(C);
table.push(C);
Declaration f1 = new Declaration("foo");
f1.setType( Declaration.t_function );
f1.setReturnType( Declaration.t_void );
f1.addParameter( Declaration.t_int, "", false );
table.addDeclaration( f1 );
Declaration f2 = new Declaration("foo");
f2.setType( Declaration.t_function );
f2.setReturnType( Declaration.t_void );
f2.addParameter( Declaration.t_int, "", false );
f2.addParameter( Declaration.t_char, "", false );
table.addDeclaration( f2 );
Declaration f3 = new Declaration("foo");
f3.setType( Declaration.t_function );
f3.setReturnType( Declaration.t_void );
f3.addParameter( Declaration.t_int, "", false );
f3.addParameter( Declaration.t_char, "", false );
f3.addParameter( C, "*", false );
table.addDeclaration( f3 );
table.pop();
Declaration look = table.Lookup("C");
assertEquals( look, C );
Declaration c = new Declaration("c");
c.setType( Declaration.t_class );
c.setTypeDeclaration( look );
table.addDeclaration( c );
look = table.Lookup( "c" );
assertEquals( look, c );
assertEquals( look.getTypeDeclaration(), C );
table.push( look.getTypeDeclaration() );
LinkedList paramList = new LinkedList();
Declaration.ParameterInfo p1 = c.new ParameterInfo(Declaration.t_int, null, "", false);
Declaration.ParameterInfo p2 = c.new ParameterInfo(Declaration.t_char, null, "", false);
Declaration.ParameterInfo p3 = c.new ParameterInfo(Declaration.t_class, C, "", false);
paramList.add( p1 );
look = table.MemberFunctionLookup( "foo", paramList );
assertEquals( look, f1 );
paramList.add( p2 );
look = table.MemberFunctionLookup( "foo", paramList );
assertEquals( look, f2 );
paramList.add( p3 );
look = table.MemberFunctionLookup( "foo", paramList );
assertEquals( look, f3 );
}
}