1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 18:56:02 +02:00

Patch for Andrew Niefer:

- Implementation of Namespaces & using directives in 
new parser's symbol table.
This commit is contained in:
Doug Schaefer 2003-03-06 18:42:26 +00:00
parent ec260cc84a
commit 5c44e281ca
4 changed files with 1303 additions and 140 deletions

View file

@ -1,13 +1,19 @@
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.internal.core.parser; package org.eclipse.cdt.internal.core.parser;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/** /**
* @author aniefer * @author aniefer
@ -17,12 +23,13 @@ import java.util.Set;
* To enable and disable the creation of type comments go to * To enable and disable the creation of type comments go to
* Window>Preferences>Java>Code Generation. * Window>Preferences>Java>Code Generation.
*/ */
public class Declaration { public class Declaration {
/** /**
* Constructor for Declaration. * Constructor for Declaration.
*/ */
public Declaration() { public Declaration(){
super(); super();
} }
@ -35,36 +42,139 @@ public class Declaration {
_object = obj; _object = obj;
} }
//Type information, only what we need for now... public static final int typeMask = 0x001f;
public static final int typeMask = 0x0001f; public static final int isAuto = 0x0020;
public static final int isStatic = 0x00020; public static final int isRegister = 0x0040;
public static final int isStatic = 0x0080;
public static final int isExtern = 0x0100;
public static final int isMutable = 0x0200;
public static final int isInline = 0x0400;
public static final int isVirtual = 0x0800;
public static final int isExplicit = 0x1000;
public static final int isTypedef = 0x2000;
public static final int isFriend = 0x4000;
public static final int isConst = 0x8000;
public static final int isVolatile = 0x10000;
public static final int isUnsigned = 0x20000;
public static final int isShort = 0x40000;
public static final int isLong = 0x80000;
public void setAuto(boolean b) { setBit(b, isAuto); }
public boolean isAuto() { return checkBit(isAuto); }
public void setRegister(boolean b) { setBit(b, isRegister); }
public boolean isRegister() { return checkBit(isRegister); }
public void setStatic(boolean b) { setBit(b, isStatic); }
public boolean isStatic() { return checkBit(isStatic); }
public void setExtern(boolean b) { setBit(b, isExtern); }
public boolean isExtern() { return checkBit(isExtern); }
public void setMutable(boolean b) { setBit(b, isMutable); }
public boolean isMutable() { return checkBit(isMutable); }
public void setInline(boolean b) { setBit(b, isInline); }
public boolean isInline() { return checkBit(isInline); }
public void setVirtual(boolean b) { setBit(b, isVirtual); }
public boolean isVirtual() { return checkBit(isVirtual); }
public void setExplicit(boolean b) { setBit(b, isExplicit); }
public boolean isExplicit() { return checkBit(isExplicit); }
public void setTypedef(boolean b) { setBit(b, isTypedef); }
public boolean isTypedef() { return checkBit(isTypedef); }
public void setFriend(boolean b) { setBit(b, isFriend); }
public boolean isFriend() { return checkBit(isFriend); }
public void setConst(boolean b) { setBit(b, isConst); }
public boolean isConst() { return checkBit(isConst); }
public void setVolatile(boolean b) { setBit(b, isVolatile); }
public boolean isVolatile() { return checkBit(isVolatile); }
public void setUnsigned(boolean b) { setBit(b, isUnsigned); }
public boolean isUnsigned() { return checkBit(isUnsigned); }
public void setShort(boolean b) { setBit(b, isShort); }
public boolean isShort() { return checkBit(isShort); }
public void setLong(boolean b) { setBit(b, isLong); }
public boolean isLong() { return checkBit(isLong); }
// Types // Types
// Note that these should be considered ordered and if you change
// the order, you should consider the ParserSymbolTable uses
public static final int t_type = 0; // Type Specifier public static final int t_type = 0; // Type Specifier
public static final int t_class = 1; public static final int t_namespace = 1;
public static final int t_struct = 2; public static final int t_class = 2;
public static final int t_union = 3; public static final int t_struct = 3;
public static final int t_enum = 4; public static final int t_union = 4;
public static final int t_enum = 5;
public static final int t_function = 6;
public static final int t_char = 7;
public static final int t_wchar_t = 8;
public static final int t_bool = 9;
public static final int t_int = 10;
public static final int t_float = 11;
public static final int t_double = 12;
public static final int t_void = 13;
public static final int t_enumerator = 14;
public void setStatic( boolean b ) { setBit( b, isStatic ); }
public boolean isStatic() { return checkBit( isStatic ); }
public void setType(int t) throws ParserSymbolTableException { public void setType(int t) throws ParserSymbolTableException{
if( t > typeMask ) //sanity check, t must fit in its allocated 5 bits in _typeInfo
if( t > typeMask ){
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo ); throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
}
_typeInfo = _typeInfo & ~typeMask | t; _typeInfo = _typeInfo & ~typeMask | t;
} }
public int getType(){ public int getType(){
return _typeInfo & typeMask; return _typeInfo & typeMask;
} }
public boolean isType( int t ){
return ( t == -1 || getType() == t ); public boolean isType( int type ){
return isType( type, 0 );
}
/**
*
* @param type
* @param upperType
* @return boolean
*
* type checking, check that this declaration's type is between type and
* upperType (inclusive). upperType of 0 means no range and our type must
* be type.
*/
public boolean isType( int type, int upperType ){
//type of -1 means we don't care
if( type == -1 )
return true;
//upperType of 0 means no range
if( upperType == 0 ){
return ( getType() == type );
} else {
return ( getType() >= type && getType() <= upperType );
}
}
public Declaration getTypeDeclaration(){
return _typeDeclaration;
} }
public Declaration getTypeDeclaration() { return _typeDeclaration; }
public void setTypeDeclaration( Declaration type ){ public void setTypeDeclaration( Declaration type ){
try { setType( t_type ); } //setting our type to a declaration implies we are type t_type
catch (ParserSymbolTableException e) { /*will never happen*/ } try {
setType( t_type );
} catch (ParserSymbolTableException e) {
/*will never happen*/
}
_typeDeclaration = type; _typeDeclaration = type;
} }
@ -76,137 +186,64 @@ public class Declaration {
public void setObject( Object obj ) { _object = obj; } public void setObject( Object obj ) { _object = obj; }
public Declaration getContainingScope() { return _containingScope; } public Declaration getContainingScope() { return _containingScope; }
protected void setContainingScope( Declaration scope ) { _containingScope = scope; } protected void setContainingScope( Declaration scope ){
_containingScope = scope;
_depth = scope._depth + 1;
}
public void addParent( Declaration parent ){ public void addParent( Declaration parent ){
addParent( parent, false ); addParent( parent, false );
} }
public void addParent( Declaration parent, boolean virtual ){ public void addParent( Declaration parent, boolean virtual ){
_parentScopes.add( new ParentWrapper( parent, virtual ) ); if( _parentScopes == null ){
_parentScopes = new LinkedList();
} }
protected void addDeclaration( Declaration obj ){ _parentScopes.add( new ParentWrapper( parent, virtual ) );
obj.setContainingScope( this );
_containedDeclarations.put( obj.getName(), obj );
} }
public Map getContainedDeclarations(){ public Map getContainedDeclarations(){
return _containedDeclarations; return _containedDeclarations;
} }
/** public Map createContained(){
* Lookup the given name in this context. if( _containedDeclarations == null )
* @param type: for elaborated lookups, only return declarations of this _containedDeclarations = new HashMap();
* type
* @param name: Name of the object to lookup
* @return Declaration
* @throws ParserSymbolTableException
* @see ParserSymbolTable#Lookup
*/
protected Declaration Lookup( int type, String name ) throws ParserSymbolTableException{
if( type != -1 && type < t_class && type > t_union ) return _containedDeclarations;
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
Declaration decl = null;
//if this name define in this scope?
decl = (Declaration) _containedDeclarations.get( name );
//if yes, it hides any others, we are done.
if( decl != null && decl.isType( type ) ){
return decl;
} }
//if no, we next check any parents we have public LinkedList getParentScopes(){
decl = LookupInParents( type, name, new HashSet() ); return _parentScopes;
//if still not found, check our containing scope.
if( decl == null && _containingScope != null )
decl = _containingScope.Lookup( type, name );
return decl;
} }
private Declaration LookupInParents( int type, String name, Set virtualsVisited ) throws ParserSymbolTableException{
Declaration decl = null, temp = null;
Iterator iterator = _parentScopes.iterator();
ParentWrapper wrapper = null;
try{
wrapper = (ParentWrapper) iterator.next();
}
catch ( NoSuchElementException e ){
wrapper = null;
}
while( wrapper != null )
{
if( !wrapper.isVirtual || !virtualsVisited.contains( wrapper.parent ) ){
if( wrapper.isVirtual )
virtualsVisited.add( wrapper.parent );
//is this name define in this scope?
temp = (Declaration) wrapper.parent._containedDeclarations.get( name );
if( temp == null || !temp.isType( type ) )
temp = wrapper.parent.LookupInParents( type, name, virtualsVisited );
}
if( temp != null && temp.isType( type ) ){
if( decl == null )
decl = temp;
else if ( temp != null )
{
//it is not ambiguous if temp & decl are the same thing and it is static
//or an enum
if( decl == temp && ( temp.isStatic() || temp.getType() == t_enum) )
temp = null;
else
throw( new ParserSymbolTableException( ParserSymbolTableException.r_AmbiguousName ) );
}
}
else
temp = null;
try{
wrapper = (ParentWrapper) iterator.next();
}
catch (NoSuchElementException e){
wrapper = null;
}
}
return decl;
}
// Convenience methods // Convenience methods
private void setBit(boolean b, int mask) { private void setBit(boolean b, int mask){
if (b) _typeInfo = _typeInfo | mask; if( b ){
else _typeInfo = _typeInfo & ~mask; _typeInfo = _typeInfo | mask;
} else {
_typeInfo = _typeInfo & ~mask;
}
} }
private boolean checkBit(int mask) { private boolean checkBit(int mask){
return (_typeInfo & mask) != 0; return (_typeInfo & mask) != 0;
} }
private int _typeInfo; //our type info
private String _name; //our name
private Object _object; //the object associated with us
private Declaration _typeDeclaration; //our type if _typeInfo says t_type
//Other scopes to check if the name is not in currRegion protected Declaration _containingScope; //the scope that contains us
//we might want another Vector to deal with namespaces & using... protected LinkedList _parentScopes; //inherited scopes (is base classes)
private Declaration _containingScope = null; protected LinkedList _usingDirectives; //collection of nominated namespaces
private Declaration _type = null; protected Map _containedDeclarations; //declarations contained by us.
private Declaration _typeDeclaration = null;
private int _typeInfo = 0;
private Object _object = null;
private List _parentScopes = new LinkedList();
private Map _containedDeclarations = new HashMap();
private String _name;
protected int _depth; //how far down the scope stack we are
private class ParentWrapper{ protected class ParentWrapper
{
public ParentWrapper( Declaration p, boolean v ){ public ParentWrapper( Declaration p, boolean v ){
parent = p; parent = p;
isVirtual = v; isVirtual = v;
@ -216,5 +253,4 @@ public class Declaration {
public Declaration parent = null; public Declaration parent = null;
} }
} }

View file

@ -1,6 +1,26 @@
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05. html
*
* Contributors:
* Rational Software - Initial API and implementation
*
***********************************************************************/
package org.eclipse.cdt.internal.core.parser; package org.eclipse.cdt.internal.core.parser;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Stack; import java.util.Stack;
/** /**
* @author aniefer * @author aniefer
* *
@ -9,6 +29,7 @@ import java.util.Stack;
* To enable and disable the creation of type comments go to * To enable and disable the creation of type comments go to
* Window>Preferences>Java>Code Generation. * Window>Preferences>Java>Code Generation.
*/ */
public class ParserSymbolTable { public class ParserSymbolTable {
/** /**
@ -21,8 +42,10 @@ public class ParserSymbolTable {
} }
public void push( Declaration obj ){ public void push( Declaration obj ){
if( _contextStack.empty() == false ) if( _contextStack.empty() == false && obj.getContainingScope() == null ){
obj.setContainingScope( (Declaration) _contextStack.peek() ); obj.setContainingScope( (Declaration) _contextStack.peek() );
}
_contextStack.push( obj ); _contextStack.push( obj );
} }
@ -34,22 +57,589 @@ public class ParserSymbolTable {
return (Declaration) _contextStack.peek(); return (Declaration) _contextStack.peek();
} }
public Declaration Lookup( String name ) throws ParserSymbolTableException {
return ( (Declaration) _contextStack.peek() ).Lookup( -1, name );
}
public Declaration ElaboratedLookup( int type, String name ) throws ParserSymbolTableException{
return ( (Declaration) _contextStack.peek() ).Lookup( type, name );
}
public void addDeclaration( Declaration obj ){
((Declaration) _contextStack.peek() ).addDeclaration( obj );
}
public Declaration getCompilationUnit(){ public Declaration getCompilationUnit(){
return _compilationUnit; return _compilationUnit;
} }
public Declaration Lookup( String name ) throws ParserSymbolTableException {
LookupData data = new LookupData( name, -1 );
return Lookup( data, (Declaration) _contextStack.peek() );
}
public Declaration ElaboratedLookup( int type, String name ) throws ParserSymbolTableException{
LookupData data = new LookupData( name, type );
return Lookup( data, (Declaration) _contextStack.peek() );
}
/**
* Method LookupNestedNameSpecifier.
* @param name
* @return Declaration
* The name of a class or namespace member can be referred to after the ::
* scope resolution operator applied to a nested-name-specifier that
* nominates its class or namespace. During the lookup for a name preceding
* the ::, object, function and enumerator names are ignored. If the name
* is not a class-name or namespace-name, the program is ill-formed
*/
public Declaration LookupNestedNameSpecifier( String name ) throws ParserSymbolTableException {
return LookupNestedNameSpecifier( name, (Declaration) _contextStack.peek() );
}
private Declaration LookupNestedNameSpecifier(String name, Declaration inDeclaration ) throws ParserSymbolTableException
{
Declaration foundDeclaration = null;
LookupData data = new LookupData( name, Declaration.t_namespace );
data.upperType = Declaration.t_union;
foundDeclaration = LookupInContained( data, inDeclaration );
if( foundDeclaration == null && inDeclaration._containingScope != null ){
foundDeclaration = LookupNestedNameSpecifier( name, inDeclaration._containingScope );
}
return foundDeclaration;
}
/**
*
* @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
{
LookupData data = new LookupData( name, -1 );
data.qualified = true;
return Lookup( data, (Declaration) _contextStack.peek() );
}
public void addUsingDirective( Declaration namespace ) throws ParserSymbolTableException
{
if( namespace.getType() != Declaration.t_namespace ){
throw new ParserSymbolTableException();
}
Declaration declaration = (Declaration) _contextStack.peek();
if( declaration._usingDirectives == null ){
declaration._usingDirectives = new LinkedList();
}
declaration._usingDirectives.add( namespace );
}
public void addDeclaration( Declaration obj ) throws ParserSymbolTableException{
Declaration containing = (Declaration) _contextStack.peek();
Map declarations = containing.getContainedDeclarations();
Object origObj = null;
obj.setContainingScope( containing );
if( declarations == null ){
declarations = containing.createContained();
} else {
//does this name exist already?
origObj = declarations.get( obj.getName() );
}
if( origObj != null )
{
Declaration origDecl = null;
LinkedList origList = null;
if( origObj.getClass() == Declaration.class ){
origDecl = (Declaration)origObj;
} else if( origObj.getClass() == LinkedList.class ){
origList = (LinkedList)origObj;
} else {
throw new ParserSymbolTableException();
}
if( (origList == null) ? isValidOverload( origDecl, obj ) : isValidOverload( origList, obj ) ){
if( origList == null ){
origList = new LinkedList();
origList.add( origDecl );
origList.add( obj );
declarations.remove( obj );
declarations.put( obj.getName(), origList );
} else {
origList.add( obj );
//origList is already in _containedDeclarations
}
} else {
throw new ParserSymbolTableException();
}
} else {
declarations.put( obj.getName(), obj );
}
}
/**
* Lookup the name from LookupData starting in the inDeclaration
* @param data
* @param inDeclaration
* @return Declaration
* @throws ParserSymbolTableException
*/
static private Declaration Lookup( LookupData data, Declaration inDeclaration ) throws ParserSymbolTableException
{
if( data.type != -1 && data.type < Declaration.t_class && data.upperType > Declaration.t_union ){
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
}
Declaration decl = null; //the return value
LinkedList tempList = null;
LinkedList foundNames = new LinkedList(); //list of names found
LinkedList transitives = new LinkedList(); //list of transitive using directives
//if this name define in this scope?
decl = LookupInContained( data, inDeclaration );
if( decl != null ){
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 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 );
if( inDeclaration._usingDirectives != null ){
ProcessDirectives( inDeclaration, data, inDeclaration._usingDirectives );
}
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 );
if( decl != null ){
return decl;
}
//if we still havn't found it, check any parents we have
data.visited.clear(); //each virtual base class is searched at most once
decl = LookupInParents( data, inDeclaration );
//if still not found, check our containing scope.
if( decl == null && inDeclaration._containingScope != null ){
decl = Lookup( data, inDeclaration._containingScope );
}
return decl;
}
/**
* function LookupInNominated
* @param data
* @param transitiveDirectives
* @return List
*
* for qualified:
* 3.4.3.2-2 "let S be the set of all declarations of m in X
* and in the transitive closure of all namespaces nominated by using-
* directives in X and its used namespaces, except that using-directives are
* ignored in any namespace, including X, directly containing one or more
* declarations of m."
*
* for unqualified:
* 7.3.4-2 The using-directive is transitive: if a scope contains a using
* directive that nominates a second namespace that itself contains using-
* directives, the effect is as if the using-directives from the second
* namespace also appeared in the first.
*/
static private LinkedList LookupInNominated( LookupData data, Declaration declaration, LinkedList transitiveDirectives ) throws ParserSymbolTableException{
//if the data.usingDirectives is empty, there is nothing to do.
if( data.usingDirectives == null ){
return null;
}
LinkedList found = null; //list of found names to return
//local variables
LinkedList list = null;
Iterator iter = null;
Declaration decl = null;
Declaration temp = null;
int size = 0;
list = (LinkedList) data.usingDirectives.remove( declaration );
if( list == null ){
return null;
}
iter = list.iterator();
size = list.size();
for( int i = size; i > 0; i-- ){
decl = (Declaration) iter.next();
//namespaces are searched at most once
if( !data.visited.contains( decl ) ){
data.visited.add( decl );
temp = LookupInContained( data, decl );
//if we found something, add it to the list of found names
if( temp != null ){
if( found == null ){
found = new LinkedList();
}
found.add( temp );
}
//only consider the transitive using directives if we are an unqualified
//lookup, or we didn't find the name in decl
if( (!data.qualified || temp == null) && decl._usingDirectives != null ){
//name wasn't found, add transitive using directives for later consideration
transitiveDirectives.addAll( decl._usingDirectives );
}
}
}
return found;
}
/**
* function LookupInContained
* @param data
* @return List
* @throws ParserSymbolTableException
*
* Look for data.name in our collection _containedDeclarations
*/
private static Declaration LookupInContained( LookupData data, Declaration lookIn ) throws ParserSymbolTableException{
LinkedList found = null;
Declaration temp = null;
Object obj = null;
Map declarations = lookIn.getContainedDeclarations();
if( declarations == null )
return null;
obj = declarations.get( data.name );
if( obj == null ){
//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 ){
if( ((Declaration)obj).isType( data.type, data.upperType ) ){
return (Declaration) obj;
}
} else {
found = new LinkedList();
LinkedList objList = (LinkedList)obj;
Iterator iter = objList.iterator();
int size = objList.size();
for( int i = 0; i < size; i++ ){
temp = (Declaration) iter.next();
if( temp.isType( data.type, data.upperType ) ){
found.add(temp);
}
}
}
//if none of the found items made it through the type filtering, just
//return null instead of an empty list.
if( found == null || found.size() == 0 )
return null;
return ResolveAmbiguities( found );
}
/**
*
* @param data
* @param lookIn
* @return Declaration
* @throws ParserSymbolTableException
*/
private static Declaration LookupInParents( LookupData data, Declaration lookIn ) throws ParserSymbolTableException{
LinkedList scopes = lookIn.getParentScopes();
Declaration decl = null;
Declaration temp = null;
Iterator iterator = null;
Declaration.ParentWrapper wrapper = null;
if( scopes == null )
return null;
iterator = scopes.iterator();
int size = scopes.size();
for( int i = size; i > 0; i-- )
{
wrapper = (Declaration.ParentWrapper) iterator.next();
if( !wrapper.isVirtual || !data.visited.contains( wrapper.parent ) ){
if( wrapper.isVirtual ){
data.visited.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.isType( data.type ) ){
if( decl == null ){
decl = temp;
} else if ( temp != null ) {
//it is not ambiguous if temp & decl are the same thing and it is static
//or an enumerator
if( decl == temp && ( temp.isStatic() || temp.getType() == Declaration.t_enumerator) ){
temp = null;
} else {
throw( new ParserSymbolTableException( ParserSymbolTableException.r_AmbiguousName ) );
}
}
} else {
temp = null; //reset temp for next iteration
}
}
return decl;
}
/**
* function isValidOverload
* @param origDecl
* @param newDecl
* @return boolean
*
* 3.3.7 "A class name or enumeration name can be hidden by the name of an
* object, function or enumerator declared in the same scope"
*
* 3.4-1 "Name lookup may associate more than one declaration with a name if
* it finds the name to be a function name"
*/
private static boolean isValidOverload( Declaration origDecl, Declaration newDecl ){
int origType = origDecl.getType();
int newType = newDecl.getType();
if( (origType >= Declaration.t_class && origType <= Declaration.t_enum) && //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;
}
private static boolean isValidOverload( LinkedList origList, Declaration newDecl ){
if( origList.size() == 1 ){
return isValidOverload( (Declaration)origList.getFirst(), newDecl );
} else if ( origList.size() > 1 ){
//the first thing can be a class-name or enumeration name, but the rest
//must be functions. So make sure the newDecl is a function before even
//considering the list
if( newDecl.getType() != Declaration.t_function ){
return false;
}
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 );
while( valid && iter.hasNext() ){
decl = (Declaration) iter.next();
valid = ( decl.getType() == Declaration.t_function );
}
return valid;
}
//empty list, return true
return true;
}
static private Declaration ResolveAmbiguities( LinkedList items ) throws ParserSymbolTableException{
Declaration decl = null;
int size = items.size();
if( size == 0){
return null;
} else if (size == 1) {
return (Declaration) items.getFirst();
} else {
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 );
}
//else, if the first is an object (ie not a function), the rest must be the same
//declaration. otherwise (ie it is a function), the rest must be functions.
boolean needSame = ( first.getType() != Declaration.t_function );
Iterator iter = items.iterator();
for( int i = (size - 1); i > 0; i-- ){
decl = (Declaration) iter.next();
if( needSame ){
if( decl != first ){
throw new ParserSymbolTableException();
}
} else {
if( decl.getType() != Declaration.t_function ){
throw new ParserSymbolTableException();
}
}
}
if( needSame ){
return first;
} else {
items.addFirst( first );
return ResolveFunction( items );
}
}
}
static private Declaration ResolveFunction( LinkedList functions ){
//TBD
return null;
}
/**
* function ProcessDirectives
* @param Declaration decl
* @param LookupData data
* @param LinkedList directives
*
* Go through the directives and for each nominated namespace find the
* closest enclosing declaration for that namespace and decl, then add the
* nominated namespace to the lookup data for consideration when we reach
* the enclosing declaration.
*/
static private void ProcessDirectives( Declaration decl, LookupData data, LinkedList directives ){
Declaration enclosing = null;
Declaration temp = null;
int size = directives.size();
Iterator iter = directives.iterator();
for( int i = size; i > 0; i-- ){
temp = (Declaration) iter.next();
//namespaces are searched at most once
if( !data.visited.contains( temp ) ){
enclosing = getClosestEnclosingDeclaration( decl, temp );
//the data.usingDirectives is a map from enclosing declaration to
//a list of namespaces to consider when we reach that enclosing
//declaration
LinkedList list = (data.usingDirectives == null )
? null
: (LinkedList) data.usingDirectives.get( enclosing );
if ( list == null ){
list = new LinkedList();
list.add( temp );
if( data.usingDirectives == null ){
data.usingDirectives = new HashMap();
}
data.usingDirectives.put( enclosing, list );
} else {
list.add( temp );
}
}
}
}
/**
* function getClosestEnclosingDeclaration
* @param decl1
* @param decl2
* @return Declaration
*
* 7.3.4-1 "During unqualified lookup, the names appear as if they were
* declared in the nearest enclosing namespace which contains both the
* using-directive and the nominated namespace"
*
* TBD: Consider rewriting this iteratively instead of recursively, for
* performance
*/
static private Declaration getClosestEnclosingDeclaration( Declaration decl1, Declaration decl2 ){
if( decl1 == decl2 ){
return decl1;
}
if( decl1._depth == decl2._depth ){
return getClosestEnclosingDeclaration( decl1._containingScope, decl2._containingScope );
} else if( decl1._depth > decl2._depth ) {
return getClosestEnclosingDeclaration( decl1._containingScope, decl2 );
} else {
return getClosestEnclosingDeclaration( decl1, decl2._containingScope );
}
}
private Stack _contextStack = new Stack(); private Stack _contextStack = new Stack();
private Declaration _compilationUnit; 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 int type = -1;
public int upperType = 0;
public boolean qualified = false;
public LookupData( String n, int t ){
name = n;
type = t;
}
}
} }

View file

@ -1,3 +1,14 @@
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.internal.core.parser; package org.eclipse.cdt.internal.core.parser;
/** /**

View file

@ -1,3 +1,14 @@
/**********************************************************************
* Copyright (c) 2002,2003 Rational Software Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Rational Software - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.core.parser.tests; package org.eclipse.cdt.core.parser.tests;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -339,7 +350,7 @@ public class ParserSymbolTableTest extends TestCase {
table.addDeclaration( d ); table.addDeclaration( d );
Declaration enum = new Declaration("enum"); Declaration enum = new Declaration("enum");
enum.setType( Declaration.t_enum ); enum.setType( Declaration.t_enumerator );
Declaration stat = new Declaration("static"); Declaration stat = new Declaration("static");
stat.setStatic(true); stat.setStatic(true);
@ -503,4 +514,519 @@ public class ParserSymbolTableTest extends TestCase {
//on just the function name without the rest of the signature //on just the function name without the rest of the signature
assertEquals( table.Lookup("foo"), null ); assertEquals( table.Lookup("foo"), null );
} }
/**
*
* @throws Exception
*
* struct stat {
* //...
* }
* int stat( struct stat* );
* void f()
* {
* struct stat *ps;
* stat(ps);
* }
*/
public void testFunctionHidesClass() throws Exception{
newTable();
Declaration struct = new Declaration( "stat");
struct.setType( Declaration.t_struct );
table.addDeclaration( struct );
Declaration function = new Declaration( "stat" );
function.setType( Declaration.t_function );
table.addDeclaration( function );
Declaration f = new Declaration("f");
f.setType( Declaration.t_function );
table.addDeclaration( f );
table.push( f );
Declaration look = table.ElaboratedLookup( Declaration.t_struct, "stat" );
assertEquals( look, struct );
look = table.Lookup( "stat" );
assertEquals( look, function );
}
/**
*
* @throws Exception
*
* namespace A {
* int i;
* namespace B {
* namespace C{
* int i;
* }
* using namespace A::B::C;
* void f1() {
* i = 5; //OK, C::i visible and hides A::i
* }
* }
* namespace D{
* using namespace B;
* using namespace C;
* void f2(){
* i = 5; //ambiguous, B::C and A::i
* }
* }
* void f3() {
* i = 5; //uses A::i
* }
* }
* void f4(){
* i = 5; //no i is visible here
* }
*
*/
public void testUsingDirectives_1() throws Exception{
newTable();
Declaration nsA = new Declaration("A");
nsA.setType( Declaration.t_namespace );
table.addDeclaration( nsA );
table.push( nsA );
Declaration nsA_i = new Declaration("i");
table.addDeclaration( nsA_i );
Declaration nsB = new Declaration("B");
nsB.setType( Declaration.t_namespace );
table.addDeclaration( nsB );
table.push( nsB );
Declaration nsC = new Declaration("C");
nsC.setType( Declaration.t_namespace );
table.addDeclaration( nsC );
table.push( nsC );
Declaration nsC_i = new Declaration("i");
table.addDeclaration( nsC_i );
table.pop();
Declaration look = table.Lookup("C");
table.addUsingDirective( look );
Declaration f1 = new Declaration("f");
f1.setType( Declaration.t_function );
table.push( f1 );
look = table.Lookup( "i" );
assertEquals( look, nsC_i ); //C::i visible and hides A::i
table.pop(); //end of f1
table.pop(); //end of nsB
assertEquals( table.peek(), nsA );
Declaration nsD = new Declaration("D");
nsD.setType( Declaration.t_namespace );
table.addDeclaration( nsD );
table.push( nsD );
look = table.Lookup("B");
assertEquals( look, nsB );
table.addUsingDirective( look );
look = table.Lookup("C");
assertEquals( look, nsC );
table.addUsingDirective( look );
Declaration f2 = new Declaration( "f2" );
f2.setType( Declaration.t_function );
table.addDeclaration( f2 );
table.push( f2 );
try
{
look = table.Lookup( "i" );
assertTrue( false );
}
catch ( ParserSymbolTableException e )
{
assertTrue(true); //ambiguous B::C::i and A::i
}
table.pop(); //end f2
table.pop(); //end nsD
Declaration f3 = new Declaration ("f3");
f3.setType( Declaration.t_function );
table.addDeclaration( f3 );
table.push( f3 );
look = table.Lookup("i");
assertEquals( look, nsA_i ); //uses A::i
table.pop();
table.pop();
Declaration f4 = new Declaration ("f4");
f4.setType( Declaration.t_function );
table.addDeclaration( f4 );
table.push( f4 );
look = table.Lookup("i");
assertEquals( look, null );//neither i is visible here.
}
/**
*
* @throws Exception
*
* namespace M {
* int i;
* }
* namespace N {
* int i;
* using namespace M;
* }
*
* void f() {
* using namespace N;
* i = 7; //error, both M::i and N::i are visible
* N::i = 5; //ok, i directly declared in N, using M not
* considered (since this is a qualified lookup)
* }
*
*/
public void testTransitiveUsingDirective() throws Exception
{
newTable();
Declaration nsM = new Declaration( "M" );
nsM.setType( Declaration.t_namespace );
table.addDeclaration( nsM );
table.push( nsM );
Declaration nsM_i = new Declaration("i");
table.addDeclaration( nsM_i );
table.pop();
Declaration nsN = new Declaration( "N" );
nsN.setType( Declaration.t_namespace );
table.addDeclaration( nsN );
table.push( nsN );
Declaration nsN_i = new Declaration("i");
table.addDeclaration( nsN_i );
table.addUsingDirective( nsM );
table.pop();
Declaration f = new Declaration("f");
table.addDeclaration( f );
table.push( f );
table.addUsingDirective( nsN );
Declaration look = null;
try
{
look = table.Lookup( "i" );
assertTrue( false );
}
catch ( ParserSymbolTableException e )
{
assertTrue( true ); //ambiguous, both M::i and N::i are visible.
}
look = table.LookupNestedNameSpecifier("N");
table.push( look );
look = table.QualifiedLookup("i"); //ok
assertEquals( look, nsN_i );
}
/**
*
* @throws Exception
* The same declaration found more than once is not an ambiguity
* namespace A{
* int a;
* }
* namespace B{
* using namespace A;
* }
* namespace C{
* using namespace A;
* }
*
* namespace BC{
* using namespace B;
* using namespace C;
* }
*
* void f(){
* BC::a++; //ok
* }
*/
public void testUsing_SameDeclarationTwice() throws Exception
{
newTable();
Declaration nsA = new Declaration("A");
nsA.setType( Declaration.t_namespace );
table.addDeclaration( nsA );
table.push( nsA );
Declaration a = new Declaration("a");
table.addDeclaration( a );
table.pop();
Declaration nsB = new Declaration("B");
nsB.setType( Declaration.t_namespace );
table.addDeclaration( nsB );
table.push( nsB );
table.addUsingDirective( nsA );
table.pop();
Declaration nsC = new Declaration("C");
nsC.setType( Declaration.t_namespace );
table.addDeclaration( nsC );
table.push( nsC );
table.addUsingDirective( nsA );
table.pop();
Declaration nsBC = new Declaration("BC");
nsBC.setType( Declaration.t_namespace );
table.addDeclaration( nsBC );
table.push( nsBC );
table.addUsingDirective( nsB );
table.addUsingDirective( nsC );
table.pop();
Declaration f = new Declaration("f");
f.setType(Declaration.t_function);
table.addDeclaration( f );
table.push(f);
Declaration look = table.LookupNestedNameSpecifier("BC");
assertEquals( look, nsBC );
table.push(look);
look = table.QualifiedLookup("a");
assertEquals( look, a );
}
/**
*
* @throws Exception
*
* namespace B {
* int b;
* }
* namespace A {
* using namespace B;
* int a;
* }
* namespace B {
* using namespace A;
* }
*
* void f(){
* A::a++; //ok
* A::b++; //ok
* B::a++; //ok
* B::b++; //ok
* }
*/
public void testUsing_SearchedOnce() throws Exception
{
newTable();
Declaration nsB = new Declaration( "B" );
nsB.setType( Declaration.t_namespace );
table.addDeclaration( nsB );
table.push( nsB );
Declaration b = new Declaration("b");
table.addDeclaration( b );
table.pop();
Declaration nsA = new Declaration( "A" );
nsA.setType( Declaration.t_namespace );
table.addDeclaration( nsA );
table.push( nsA );
table.addUsingDirective( nsB );
Declaration a = new Declaration("a");
table.addDeclaration( a );
table.pop();
table.push( nsB );
table.addUsingDirective( nsA );
table.pop();
Declaration f = new Declaration("f");
table.addDeclaration(f);
table.push(f);
Declaration look = table.LookupNestedNameSpecifier("A");
table.push(look);
look = table.QualifiedLookup("a");
assertEquals( look, a );
look = table.QualifiedLookup("b");
assertEquals( look, b );
table.pop();
look = table.LookupNestedNameSpecifier("B");
table.push(look);
look = table.QualifiedLookup("a");
assertEquals( look, a );
look = table.QualifiedLookup("b");
assertEquals( look, b );
table.pop();
}
/**
* we pass if we don't go into an infinite loop.
* TBD: we need a mechanism to detect failure of this
* test instead of just looping forever.
*
* @throws Exception
*
* namespace A{
* }
* namespace B{
* using namespace A;
* }
* namespace A{
* using namespace B;
* }
* void f(){
* using namespace A;
* using namespace B;
* i = 1; //not declared anywhere.
* }
*/
public void testUsing_SearchedOnce_2() throws Exception
{
newTable();
Declaration nsA = new Declaration( "A" );
nsA.setType( Declaration.t_namespace );
table.addDeclaration( nsA );
Declaration nsB = new Declaration( "B" );
nsB.setType( Declaration.t_namespace );
table.addDeclaration( nsB );
table.push( nsB );
table.addUsingDirective( nsA );
table.pop();
table.push( nsA );
table.addUsingDirective( nsB );
table.pop();
Declaration f = new Declaration("f");
table.addDeclaration(f);
table.push(f);
table.addUsingDirective(nsA);
table.addUsingDirective(nsB);
Declaration look = table.Lookup("i");
assertEquals( look, null );
}
/**
* During lookup of a qualified namespace member name, if the lookup finds
* more than one declaration of the member, non-type names hide class or
* enumeration names if and only if the declarations are from the same
* namespace
* @throws Exception
*
* namespace A {
* struct x { };
* int x;
* int y;
* }
* namespace B {
* struct y { };
* }
*
* namespace C {
* using namespace A;
* using namespace B;
*
* int i = C::x; //ok, finds A::x
* int j = C::y; //ambiguous, A::y or B::y
* }
*/
public void testNamespaceMemberHiding() throws Exception{
newTable();
Declaration nsA = new Declaration("A");
nsA.setType( Declaration.t_namespace );
table.addDeclaration( nsA );
table.push( nsA );
Declaration structX = new Declaration("x");
structX.setType( Declaration.t_struct );
table.addDeclaration( structX );
Declaration intX = new Declaration("x");
intX.setType( Declaration.t_int );
table.addDeclaration( intX );
Declaration intY = new Declaration("y");
intY.setType( Declaration.t_int );
table.addDeclaration( intY );
table.pop();
Declaration nsB = new Declaration("B");
nsB.setType( Declaration.t_namespace );
table.addDeclaration( nsB );
table.push( nsB );
Declaration structY = new Declaration("y");
structY.setType( Declaration.t_struct );
table.addDeclaration( structY );
table.pop();
Declaration nsC = new Declaration("C");
nsC.setType( Declaration.t_namespace);
table.addDeclaration( nsC );
table.push( nsC );
Declaration look = table.Lookup("A");
assertEquals( look, nsA );
table.addUsingDirective( look );
look = table.Lookup("B");
assertEquals( look, nsB );
table.addUsingDirective( look );
//lookup C::x
look = table.LookupNestedNameSpecifier("C");
assertEquals( look, nsC );
table.push(look);
look = table.QualifiedLookup( "x" );
assertEquals( look, intX );
table.pop();
//lookup C::y
look = table.LookupNestedNameSpecifier("C");
assertEquals( look, nsC );
table.push(look);
try{
look = table.QualifiedLookup( "y" );
assertTrue(false);
} catch ( Exception e ) {
assertTrue(true);
}
}
} }