mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-24 01:15:29 +02:00
Patch for Andrew Niefer:
Patch for the parser's symbol table. -friends -"this" pointer -enumerators -argument dependent lookup -function parameters & function overloading
This commit is contained in:
parent
e92cfae068
commit
c27351afc0
5 changed files with 1311 additions and 124 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue