[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[cdt-patch] Implementation of Namespaces & using directives in ne w parser's symbol table
|
patch_03.05.03(cdt.core).txt contains the new parser's ParserSymbolTable
implementation of lookup of names in namespaces nominated by using
directives.
patch_03.05.03(cdt.ui.tests).txt contains the corresponding junit tests.
Andrew Niefer
Software Engineer
Rational Software - IBM Software Group
Ottawa (Kanata), Ontario, Canada
Index: parser/org/eclipse/cdt/internal/core/parser/Declaration.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java,v
retrieving revision 1.2
diff -u -r1.2 Declaration.java
--- parser/org/eclipse/cdt/internal/core/parser/Declaration.java 4 Mar 2003 18:25:40 -0000 1.2
+++ parser/org/eclipse/cdt/internal/core/parser/Declaration.java 5 Mar 2003 22:55:30 -0000
@@ -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;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
/**
* @author aniefer
@@ -17,12 +23,13 @@
* To enable and disable the creation of type comments go to
* Window>Preferences>Java>Code Generation.
*/
+
public class Declaration {
/**
* Constructor for Declaration.
*/
- public Declaration() {
+ public Declaration(){
super();
}
@@ -35,36 +42,139 @@
_object = obj;
}
- //Type information, only what we need for now...
- public static final int typeMask = 0x0001f;
- public static final int isStatic = 0x00020;
-
- // Types
- public static final int t_type = 0; // Type Specifier
- public static final int t_class = 1;
- public static final int t_struct = 2;
- public static final int t_union = 3;
- public static final int t_enum = 4;
+ public static final int typeMask = 0x001f;
+ public static final int isAuto = 0x0020;
+ 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 setStatic( boolean b ) { setBit( b, isStatic ); }
- public boolean isStatic() { return checkBit( isStatic ); }
+ 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 setType(int t) throws ParserSymbolTableException {
- if( t > typeMask )
+ public void setLong(boolean b) { setBit(b, isLong); }
+ public boolean isLong() { return checkBit(isLong); }
+
+ // 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_namespace = 1;
+ 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_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 setType(int t) throws ParserSymbolTableException{
+ //sanity check, t must fit in its allocated 5 bits in _typeInfo
+ if( t > typeMask ){
throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
+ }
+
_typeInfo = _typeInfo & ~typeMask | t;
}
+
public int getType(){
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 ){
- try { setType( t_type ); }
- catch (ParserSymbolTableException e) { /*will never happen*/ }
+ //setting our type to a declaration implies we are type t_type
+ try {
+ setType( t_type );
+ } catch (ParserSymbolTableException e) {
+ /*will never happen*/
+ }
_typeDeclaration = type;
}
@@ -76,137 +186,64 @@
public void setObject( Object obj ) { _object = obj; }
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 ){
addParent( parent, false );
}
public void addParent( Declaration parent, boolean virtual ){
+ if( _parentScopes == null ){
+ _parentScopes = new LinkedList();
+ }
+
_parentScopes.add( new ParentWrapper( parent, virtual ) );
}
-
- protected void addDeclaration( Declaration obj ){
- obj.setContainingScope( this );
- _containedDeclarations.put( obj.getName(), obj );
- }
public Map getContainedDeclarations(){
return _containedDeclarations;
}
- /**
- * Lookup the given name in this context.
- * @param type: for elaborated lookups, only return declarations of this
- * 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 )
- throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo );
-
- Declaration decl = null;
-
- //if this name define in this scope?
- decl = (Declaration) _containedDeclarations.get( name );
+ public Map createContained(){
+ if( _containedDeclarations == null )
+ _containedDeclarations = new HashMap();
- //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
- decl = LookupInParents( type, name, new HashSet() );
-
- //if still not found, check our containing scope.
- if( decl == null && _containingScope != null )
- decl = _containingScope.Lookup( type, name );
-
- return decl;
+ return _containedDeclarations;
}
- 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;
+ public LinkedList getParentScopes(){
+ return _parentScopes;
}
-
// Convenience methods
- private void setBit(boolean b, int mask) {
- if (b) _typeInfo = _typeInfo | mask;
- else _typeInfo = _typeInfo & ~mask;
+ private void setBit(boolean b, int mask){
+ if( b ){
+ _typeInfo = _typeInfo | mask;
+ } else {
+ _typeInfo = _typeInfo & ~mask;
+ }
}
- private boolean checkBit(int mask) {
+ private boolean checkBit(int mask){
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
+
+ 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.
- //Other scopes to check if the name is not in currRegion
- //we might want another Vector to deal with namespaces & using...
- private Declaration _containingScope = null;
- private Declaration _type = null;
- 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 ){
parent = p;
isVirtual = v;
@@ -215,6 +252,5 @@
public boolean isVirtual = false;
public Declaration parent = null;
}
-
-
+
}
Index: parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java,v
retrieving revision 1.2
diff -u -r1.2 ParserSymbolTable.java
--- parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java 4 Mar 2003 18:25:40 -0000 1.2
+++ parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java 5 Mar 2003 22:55:31 -0000
@@ -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;
+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;
+
/**
* @author aniefer
*
@@ -9,6 +29,7 @@
* To enable and disable the creation of type comments go to
* Window>Preferences>Java>Code Generation.
*/
+
public class ParserSymbolTable {
/**
@@ -21,8 +42,10 @@
}
public void push( Declaration obj ){
- if( _contextStack.empty() == false )
+ if( _contextStack.empty() == false && obj.getContainingScope() == null ){
obj.setContainingScope( (Declaration) _contextStack.peek() );
+ }
+
_contextStack.push( obj );
}
@@ -34,22 +57,589 @@
return (Declaration) _contextStack.peek();
}
+ public Declaration getCompilationUnit(){
+ return _compilationUnit;
+ }
+
public Declaration Lookup( String name ) throws ParserSymbolTableException {
- return ( (Declaration) _contextStack.peek() ).Lookup( -1, name );
+ LookupData data = new LookupData( name, -1 );
+ return Lookup( data, (Declaration) _contextStack.peek() );
}
public Declaration ElaboratedLookup( int type, String name ) throws ParserSymbolTableException{
- return ( (Declaration) _contextStack.peek() ).Lookup( type, name );
+ 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 void addDeclaration( Declaration obj ){
- ((Declaration) _contextStack.peek() ).addDeclaration( obj );
+ 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;
}
- public Declaration getCompilationUnit(){
- return _compilationUnit;
+ /**
+ *
+ * @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 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;
+ }
+ }
}
Index: parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java,v
retrieving revision 1.2
diff -u -r1.2 ParserSymbolTableException.java
--- parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java 4 Mar 2003 18:25:40 -0000 1.2
+++ parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java 5 Mar 2003 22:55:31 -0000
@@ -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;
/**
Index: parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java,v
retrieving revision 1.2
diff -u -r1.2 ParserSymbolTableTest.java
--- parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java 4 Mar 2003 18:25:44 -0000 1.2
+++ parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java 5 Mar 2003 22:56:08 -0000
@@ -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;
import junit.framework.TestCase;
@@ -333,7 +344,7 @@
table.addDeclaration( d );
Declaration enum = new Declaration("enum");
- enum.setType( Declaration.t_enum );
+ enum.setType( Declaration.t_enumerator );
Declaration stat = new Declaration("static");
stat.setStatic(true);
@@ -496,5 +507,519 @@
//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
+ *
+ * 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);
+ }
}
}