From c27351afc006a281288d8636d98a881449522b1b Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Sun, 23 Mar 2003 14:00:00 +0000 Subject: [PATCH] Patch for Andrew Niefer: Patch for the parser's symbol table. -friends -"this" pointer -enumerators -argument dependent lookup -function parameters & function overloading --- core/org.eclipse.cdt.core/parser/ChangeLog | 8 + .../cdt/internal/core/parser/Declaration.java | 164 ++++- .../core/parser/ParserSymbolTable.java | 621 +++++++++++++++-- .../parser/ParserSymbolTableException.java | 8 +- .../parser/tests/ParserSymbolTableTest.java | 634 ++++++++++++++++-- 5 files changed, 1311 insertions(+), 124 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/ChangeLog b/core/org.eclipse.cdt.core/parser/ChangeLog index ee6e1c4350b..3195f45b37e 100644 --- a/core/org.eclipse.cdt.core/parser/ChangeLog +++ b/core/org.eclipse.cdt.core/parser/ChangeLog @@ -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. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java index 5ef69590f47..f50df25cb98 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java @@ -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; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java index e0bb08333b9..b75d62d5117 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java index efe87c21833..89fc8e1bc33 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java @@ -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; } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java index 32da81906ff..d409456858b 100644 --- a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java +++ b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java @@ -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 ); + } }