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:
parent
ec260cc84a
commit
5c44e281ca
4 changed files with 1303 additions and 140 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue