1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-11 18:25:40 +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 2003-03-19 John Camelon
Updated Parser method visibility to solidify external interface. Updated Parser method visibility to solidify external interface.
Solved and removed TODO's from Scanner implementation. 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.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.Iterator;
/** /**
* @author aniefer * @author aniefer
@ -24,7 +25,7 @@ import java.util.Map;
* Window>Preferences>Java>Code Generation. * Window>Preferences>Java>Code Generation.
*/ */
public class Declaration { public class Declaration implements Cloneable {
/** /**
* Constructor for Declaration. * Constructor for Declaration.
@ -42,6 +43,40 @@ public class Declaration {
_object = obj; _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 typeMask = 0x001f;
public static final int isAuto = 0x0020; public static final int isAuto = 0x0020;
public static final int isRegister = 0x0040; 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_class = 2;
public static final int t_struct = 3; public static final int t_struct = 3;
public static final int t_union = 4; 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_function = 6;
public static final int t_char = 7; public static final int t_char = 7;
public static final int t_wchar_t = 8; public static final int t_wchar_t = 8;
@ -169,13 +204,6 @@ public class Declaration {
} }
public void setTypeDeclaration( Declaration type ){ 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; _typeDeclaration = type;
} }
@ -217,6 +245,93 @@ public class Declaration {
return _parentScopes; 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 // Convenience methods
private void setBit(boolean b, int mask){ private void setBit(boolean b, int mask){
if( b ){ if( b ){
@ -234,11 +349,16 @@ public class Declaration {
private String _name; //our name private String _name; //our name
private Object _object; //the object associated with us private Object _object; //the object associated with us
private Declaration _typeDeclaration; //our type if _typeInfo says t_type 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 Declaration _containingScope; //the scope that contains us
protected LinkedList _parentScopes; //inherited scopes (is base classes) protected LinkedList _parentScopes; //inherited scopes (is base classes)
protected LinkedList _usingDirectives; //collection of nominated namespaces 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 protected int _depth; //how far down the scope stack we are
@ -253,4 +373,26 @@ public class Declaration {
public Declaration parent = null; 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.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Stack; import java.util.Stack;
@ -38,6 +39,12 @@ public class ParserSymbolTable {
public ParserSymbolTable() { public ParserSymbolTable() {
super(); super();
_compilationUnit = new Declaration(); _compilationUnit = new Declaration();
try{
_compilationUnit.setType( Declaration.t_namespace );
} catch ( ParserSymbolTableException e ){
/*shouldn't happen*/
}
push( _compilationUnit ); push( _compilationUnit );
} }
@ -86,8 +93,7 @@ public class ParserSymbolTable {
return LookupNestedNameSpecifier( name, (Declaration) _contextStack.peek() ); 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; Declaration foundDeclaration = null;
LookupData data = new LookupData( name, Declaration.t_namespace ); LookupData data = new LookupData( name, Declaration.t_namespace );
@ -102,26 +108,203 @@ public class ParserSymbolTable {
return foundDeclaration; 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 * @param name
* @return Declaration * @return Declaration
* @throws ParserSymbolTableException * @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 ); LookupData data = new LookupData( name, -1 );
data.qualified = true; data.qualified = true;
return Lookup( data, (Declaration) _contextStack.peek() ); 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 ){ if( namespace.getType() != Declaration.t_namespace ){
throw new ParserSymbolTableException(); throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
} }
Declaration declaration = (Declaration) _contextStack.peek(); Declaration declaration = (Declaration) _contextStack.peek();
@ -133,10 +316,77 @@ public class ParserSymbolTable {
declaration._usingDirectives.add( namespace ); 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{ public void addDeclaration( Declaration obj ) throws ParserSymbolTableException{
Declaration containing = (Declaration) _contextStack.peek(); 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(); Map declarations = containing.getContainedDeclarations();
boolean unnamed = obj.getName().equals( "" );
Object origObj = null; Object origObj = null;
obj.setContainingScope( containing ); obj.setContainingScope( containing );
@ -161,7 +411,7 @@ public class ParserSymbolTable {
throw new ParserSymbolTableException(); 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 ){ if( origList == null ){
origList = new LinkedList(); origList = new LinkedList();
origList.add( origDecl ); origList.add( origDecl );
@ -174,11 +424,84 @@ public class ParserSymbolTable {
//origList is already in _containedDeclarations //origList is already in _containedDeclarations
} }
} else { } else {
throw new ParserSymbolTableException(); throw new ParserSymbolTableException( ParserSymbolTableException.r_InvalidOverload );
} }
} else { } else {
declarations.put( obj.getName(), obj ); 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,6 +529,7 @@ public class ParserSymbolTable {
foundNames.add( decl ); foundNames.add( decl );
} }
if( !data.ignoreUsingDirectives ){
//check nominated namespaces //check nominated namespaces
//the transitives list is populated in LookupInNominated, and then //the transitives list is populated in LookupInNominated, and then
//processed in ProcessDirectives //processed in ProcessDirectives
@ -219,7 +543,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. //we haven't found the name yet (and if we aren't ignoring them).
if( !data.qualified || foundNames.size() == 0 ){ if( !data.qualified || foundNames.size() == 0 ){
ProcessDirectives( inDeclaration, data, transitives ); ProcessDirectives( inDeclaration, data, transitives );
@ -241,8 +565,9 @@ public class ParserSymbolTable {
} }
} }
} }
}
decl = ResolveAmbiguities( foundNames ); decl = ResolveAmbiguities( data, foundNames );
if( decl != null ){ if( decl != null ){
return decl; return decl;
} }
@ -343,6 +668,11 @@ public class ParserSymbolTable {
Declaration temp = null; Declaration temp = null;
Object obj = 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(); Map declarations = lookIn.getContainedDeclarations();
if( declarations == null ) if( declarations == null )
return null; return null;
@ -381,7 +711,7 @@ public class ParserSymbolTable {
if( found == null || found.size() == 0 ) if( found == null || found.size() == 0 )
return null; 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{ private static Declaration LookupInParents( LookupData data, Declaration lookIn ) throws ParserSymbolTableException{
LinkedList scopes = lookIn.getParentScopes(); LinkedList scopes = lookIn.getParentScopes();
Declaration decl = null;
Declaration temp = null; Declaration temp = null;
Declaration decl = null;
Iterator iterator = null; Iterator iterator = null;
Declaration.ParentWrapper wrapper = null; Declaration.ParentWrapper wrapper = null;
if( scopes == null ) if( scopes == null )
return null; return null;
//use data to detect circular inheritance
if( data.inheritanceChain == null )
data.inheritanceChain = new HashSet();
data.inheritanceChain.add( lookIn );
iterator = scopes.iterator(); iterator = scopes.iterator();
int size = scopes.size(); int size = scopes.size();
@ -413,15 +750,27 @@ public class ParserSymbolTable {
data.visited.add( wrapper.parent ); data.visited.add( 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? //is this name define in this scope?
temp = LookupInContained( data, wrapper.parent ); temp = LookupInContained( data, wrapper.parent );
if( temp == null ){ if( temp == null ){
temp = LookupInParents( data, wrapper.parent ); 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( temp != null && temp.isType( data.type ) ){
if( decl == null ){ if( decl == null ){
decl = temp; decl = temp;
} else if ( temp != null ) { } else if ( temp != null ) {
@ -458,18 +807,14 @@ public class ParserSymbolTable {
int origType = origDecl.getType(); int origType = origDecl.getType();
int newType = newDecl.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) ) ){ ( newType == Declaration.t_type || (newType >= Declaration.t_function && newType <= Declaration.typeMask) ) ){
return true; return true;
} }
//if the origtype is not a class-name or enumeration name, then the only other //if the origtype is not a class-name or enumeration name, then the only other
//allowable thing is if they are both functions. //allowable thing is if they are both functions.
else if( origType == Declaration.t_function && newType == Declaration.t_function ){ return isValidFunctionOverload( origDecl, newDecl );
return true;
}
return false;
} }
private static boolean isValidOverload( LinkedList origList, Declaration newDecl ){ private static boolean isValidOverload( LinkedList origList, Declaration newDecl ){
@ -486,12 +831,12 @@ public class ParserSymbolTable {
Iterator iter = origList.iterator(); Iterator iter = origList.iterator();
Declaration decl = (Declaration) iter.next(); Declaration decl = (Declaration) iter.next();
boolean valid = (( decl.getType() >= Declaration.t_class && decl.getType() <= Declaration.t_enum ) || boolean valid = (( decl.getType() >= Declaration.t_class && decl.getType() <= Declaration.t_enumeration ) ||
decl.getType() == Declaration.t_function ); isValidFunctionOverload( decl, newDecl ));
while( valid && iter.hasNext() ){ while( valid && iter.hasNext() ){
decl = (Declaration) iter.next(); decl = (Declaration) iter.next();
valid = ( decl.getType() == Declaration.t_function ); valid = isValidFunctionOverload( decl, newDecl );
} }
return valid; return valid;
@ -501,7 +846,31 @@ public class ParserSymbolTable {
return true; 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; Declaration decl = null;
int size = items.size(); int size = items.size();
@ -514,8 +883,8 @@ public class ParserSymbolTable {
Declaration first = (Declaration)items.removeFirst(); Declaration first = (Declaration)items.removeFirst();
//if first one is a class-name, the next ones hide it //if first one is a class-name, the next ones hide it
if( first.getType() >= Declaration.t_class && first.getType() <= Declaration.t_enum ){ if( first.getType() >= Declaration.t_class && first.getType() <= Declaration.t_enumeration ){
return ResolveAmbiguities( items ); return ResolveAmbiguities( data, items );
} }
//else, if the first is an object (ie not a function), the rest must be the same //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( needSame ){
if( decl != first ){ if( decl != first ){
throw new ParserSymbolTableException(); throw new ParserSymbolTableException( ParserSymbolTableException.r_AmbiguousName );
} }
} else { } else {
if( decl.getType() != Declaration.t_function ){ if( decl.getType() != Declaration.t_function ){
throw new ParserSymbolTableException(); throw new ParserSymbolTableException( ParserSymbolTableException.r_AmbiguousName );
} }
} }
} }
@ -542,15 +911,62 @@ public class ParserSymbolTable {
return first; return first;
} else { } else {
items.addFirst( first ); items.addFirst( first );
return ResolveFunction( items ); return ResolveFunction( data, items );
} }
} }
} }
static private Declaration ResolveFunction( LinkedList functions ){ static private Declaration ResolveFunction( LookupData data, LinkedList functions ){
//TBD
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; return null;
} }
else if( size == 1) {
return (Declaration) functions.getFirst();
}
return null;
}
/** /**
* function ProcessDirectives * function ProcessDirectives
@ -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 Stack _contextStack = new Stack();
private Declaration _compilationUnit; private Declaration _compilationUnit;
private class LookupData private class LookupData
{ {
public String name; public String name;
public Map usingDirectives; public Map usingDirectives;
public Set visited = new HashSet(); //used to ensure we don't visit things more than once 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 type = -1;
public int upperType = 0; public int upperType = 0;
public boolean qualified = false; public boolean qualified = false;
public boolean ignoreUsingDirectives = false;
public LookupData( String n, int t ){ public LookupData( String n, int t ){
name = n; name = n;

View file

@ -39,6 +39,8 @@ public class ParserSymbolTableException extends Exception {
public static final int r_Unspecified = -1; public static final int r_Unspecified = -1;
public static final int r_AmbiguousName = 0; public static final int r_AmbiguousName = 0;
public static final int r_BadTypeInfo = 1; 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; public int reason = -1;
} }

View file

@ -12,6 +12,7 @@
package org.eclipse.cdt.core.parser.tests; package org.eclipse.cdt.core.parser.tests;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import junit.framework.TestCase; 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 * testVirtualParentLookup
* *
@ -320,7 +348,7 @@ public class ParserSymbolTableTest extends TestCase {
assertTrue( false ); assertTrue( false );
} }
catch( ParserSymbolTableException e){ catch( ParserSymbolTableException e){
assertTrue( true ); assertEquals( e.reason, ParserSymbolTableException.r_AmbiguousName );
} }
} }
@ -351,7 +379,10 @@ public class ParserSymbolTableTest extends TestCase {
table.addDeclaration( d ); table.addDeclaration( d );
Declaration enum = new Declaration("enum"); 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"); Declaration stat = new Declaration("static");
stat.setStatic(true); stat.setStatic(true);
@ -360,6 +391,9 @@ public class ParserSymbolTableTest extends TestCase {
table.push(d); table.push(d);
table.addDeclaration( enum ); table.addDeclaration( enum );
table.push( enum );
table.addDeclaration( enumerator );
table.pop();
table.addDeclaration( stat ); table.addDeclaration( stat );
table.addDeclaration( x ); table.addDeclaration( x );
table.pop(); table.pop();
@ -371,7 +405,7 @@ public class ParserSymbolTableTest extends TestCase {
table.push( a ); table.push( a );
try{ try{
table.Lookup( "enum" ); table.Lookup( "enumerator" );
assertTrue( true ); assertTrue( true );
} }
catch ( ParserSymbolTableException e){ catch ( ParserSymbolTableException e){
@ -391,7 +425,7 @@ public class ParserSymbolTableTest extends TestCase {
assertTrue( false ); assertTrue( false );
} }
catch ( ParserSymbolTableException e){ catch ( ParserSymbolTableException e){
assertTrue( true ); assertEquals( e.reason, ParserSymbolTableException.r_AmbiguousName );
} }
} }
@ -476,46 +510,6 @@ public class ParserSymbolTableTest extends TestCase {
assertEquals( look, member ); 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 * @throws Exception
@ -649,7 +643,8 @@ public class ParserSymbolTableTest extends TestCase {
} }
catch ( ParserSymbolTableException e ) 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 f2
table.pop(); //end nsD table.pop(); //end nsD
@ -732,7 +727,8 @@ public class ParserSymbolTableTest extends TestCase {
} }
catch ( ParserSymbolTableException e ) 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"); look = table.LookupNestedNameSpecifier("N");
@ -1025,9 +1021,551 @@ public class ParserSymbolTableTest extends TestCase {
try{ try{
look = table.QualifiedLookup( "y" ); look = table.QualifiedLookup( "y" );
assertTrue(false); assertTrue(false);
} catch ( Exception e ) { } catch ( ParserSymbolTableException e ) {
assertTrue(true); 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 );
}
} }