diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java index 9822fb9c391..59fbed2814b 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java @@ -274,7 +274,7 @@ public class AST2BaseTest extends TestCase { if( collector.getName( i ).resolveBinding() == binding ) count++; - assertEquals( count, num ); + assertEquals( num, count ); } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index f68290a53ec..d3662b4ca93 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -1310,5 +1310,61 @@ public class AST2CPPTests extends AST2BaseTest { assertTrue( CharArrayUtils.equals( T.getNameCharArray(), "T".toCharArray() ) ) ; //$NON-NLS-1$ assertEquals( T.getName(), "T" ); //$NON-NLS-1$ } + + public void testArgumentDependantLookup() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("namespace NS { \n"); //$NON-NLS-1$ + buffer.append(" class T {}; \n"); //$NON-NLS-1$ + buffer.append(" void f( T ); \n"); //$NON-NLS-1$ + buffer.append("} \n"); //$NON-NLS-1$ + buffer.append("NS::T parm; \n"); //$NON-NLS-1$ + buffer.append("int main() { \n"); //$NON-NLS-1$ + buffer.append(" f( parm ); \n"); //$NON-NLS-1$ + buffer.append("} \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); //$NON-NLS-1$ + CPPNameCollector col = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit(tu, col); + + ICPPNamespace NS = (ICPPNamespace) col.getName(0).resolveBinding(); + ICPPClassType T = (ICPPClassType) col.getName(1).resolveBinding(); + IFunction f = (IFunction) col.getName(2).resolveBinding(); + IVariable parm = (IVariable) col.getName(8).resolveBinding(); + + assertInstances( col, NS, 2 ); + assertInstances( col, T, 4 ); + assertInstances( col, f, 2 ); + assertInstances( col, parm, 2 ); + } + + public void testArgumentDependantLookup_2() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("namespace NS1{ \n" ); //$NON-NLS-1$ + buffer.append(" void f( void * ); \n" ); //$NON-NLS-1$ + buffer.append("} \n" ); //$NON-NLS-1$ + buffer.append("namespace NS2{ \n" ); //$NON-NLS-1$ + buffer.append(" using namespace NS1; \n" ); //$NON-NLS-1$ + buffer.append(" class B {}; \n" ); //$NON-NLS-1$ + buffer.append(" void f( void * ); \n" ); //$NON-NLS-1$ + buffer.append("} \n" ); //$NON-NLS-1$ + buffer.append("class A : public NS2::B {} *a; \n" ); //$NON-NLS-1$ + buffer.append("int main() { \n" ); //$NON-NLS-1$ + buffer.append(" f( a ); \n" ); //$NON-NLS-1$ + buffer.append("} \n" ); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); + CPPNameCollector col = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit(tu, col); + + IFunction fref = (IFunction) col.getName(14).resolveBinding(); + IFunction f1 = (IFunction) col.getName(1).resolveBinding(); + IFunction f2 = (IFunction) col.getName(6).resolveBinding(); + + assertSame( f2, fref ); + assertNotNull( f1 ); + assertNotNull( f2 ); + + + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java index 4d464e12777..9c416e31c4d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java @@ -65,7 +65,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; @@ -106,9 +105,11 @@ public class CPPSemantics { public ObjectMap usingDirectives = ObjectMap.EMPTY_MAP; public ObjectSet visited = ObjectSet.EMPTY_SET; //used to ensure we don't visit things more than once public ObjectSet inheritanceChain; //used to detect circular inheritance + public ObjectSet associated = ObjectSet.EMPTY_SET; public boolean ignoreUsingDirectives = false; public boolean usingDirectivesOnly = false; + public boolean forceQualified = false; public List foundItems = null; public Object [] functionParameters; public boolean forUserDefinedConversion; @@ -176,6 +177,7 @@ public class CPPSemantics { return false; } public boolean qualified(){ + if( forceQualified ) return true; if( astName == null ) return false; IASTNode p1 = astName.getParent(); if( p1 instanceof ICPPASTQualifiedName ){ @@ -183,6 +185,13 @@ public class CPPSemantics { } return p1 instanceof ICPPASTFieldReference; } + public boolean functionCall(){ + if( astName == null ) return false; + IASTNode p1 = astName.getParent(); + if( p1 instanceof ICPPASTQualifiedName ) + p1 = p1.getParent(); + return ( p1 instanceof IASTIdExpression && p1.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME ); + } } static protected class Cost @@ -316,21 +325,9 @@ public class CPPSemantics { } } static protected IBinding resolveBinding( IASTName name ){ - if( name instanceof ICPPASTQualifiedName && ((ICPPASTQualifiedName)name).isFullyQualified() ) - return ((ICPPASTTranslationUnit)name.getTranslationUnit()).resolveBinding(); +// if( name instanceof ICPPASTQualifiedName && ((ICPPASTQualifiedName)name).isFullyQualified() ) +// return ((ICPPASTTranslationUnit)name.getTranslationUnit()).resolveBinding(); -// if( name.toCharArray().length == 2 && CharArrayUtils.equals( name.toCharArray(), Keywords.cpCOLONCOLON ) ){ -// IASTNode node = name.getParent(); -// if( node instanceof ICPPASTQualifiedName ){ -// ICPPASTQualifiedName qname = (ICPPASTQualifiedName) node; -// if( qname.getNames()[0] == name ){ -// //translation unit -// return ((ICPPASTTranslationUnit)node.getTranslationUnit()).resolveBinding(); -// } -// } -// return null; -// } - //1: get some context info off of the name to figure out what kind of lookup we want LookupData data = createLookupData( name ); @@ -363,6 +360,27 @@ public class CPPSemantics { * @return */ private static IBinding postResolution( IBinding binding, LookupData data ) { + if( !(data.astName instanceof ICPPASTQualifiedName) && data.functionCall() ){ + //3.4.2 argument dependent name lookup, aka Koenig lookup + try { + IScope scope = (binding != null ) ? binding.getScope() : null; + if( data.associated.size() > 0 && ( scope == null|| !(scope instanceof ICPPClassScope) ) ){ + Object [] assoc = new Object[ data.associated.size() ]; + System.arraycopy( data.associated.keyArray(), 0, assoc, 0, assoc.length ); + data.ignoreUsingDirectives = true; + data.forceQualified = true; + for( int i = 0; i < assoc.length; i++ ){ + if( data.associated.containsKey( assoc[i] ) ) + lookup( data, assoc[i] ); + } + + binding = resolveAmbiguities( data, data.astName ); + } + } catch ( DOMException e ) { + binding = e.getProblem(); + } + } + if( binding instanceof ICPPClassType && data.considerConstructors() ){ ICPPClassType cls = (ICPPClassType) binding; try { @@ -434,9 +452,65 @@ public class CPPSemantics { data.functionParameters = fdtor.getParameters(); } } + + if( !(name.getParent() instanceof ICPPASTQualifiedName) && data.functionCall() ){ + data.associated = getAssociatedScopes( data ); + } + return data; } + + static private ObjectSet getAssociatedScopes( LookupData data ) { + Object [] ps = data.functionParameters; + ObjectSet namespaces = new ObjectSet(2); + ObjectSet classes = new ObjectSet(2); + for( int i = 0; i < ps.length; i++ ){ + IType p = getSourceParameterType( ps, i ); + p = getUltimateType( p ); + try { + getAssociatedScopes( p, namespaces, classes ); + } catch ( DOMException e ) { + } + } + return namespaces; + } + static private void getAssociatedScopes( IType t, ObjectSet namespaces, ObjectSet classes ) throws DOMException{ + //3.4.2-2 + if( t instanceof ICPPClassType ){ + if( !classes.containsKey( t ) ){ + classes.put( t ); + namespaces.put( getContainingNamespaceScope( (IBinding) t ) ); + + ICPPClassType cls = (ICPPClassType) t; + ICPPBase[] bases = cls.getBases(); + for( int i = 0; i < bases.length; i++ ){ + getAssociatedScopes( bases[i].getBaseClass(), namespaces, classes ); + } + } + } else if( t instanceof IEnumeration ){ + namespaces.put( getContainingNamespaceScope( (IBinding) t ) ); + } else if( t instanceof IFunctionType ){ + IFunctionType ft = (IFunctionType) t; + + getAssociatedScopes( getUltimateType( ft.getReturnType() ), namespaces, classes ); + IType [] ps = ft.getParameterTypes(); + for( int i = 0; i < ps.length; i++ ){ + getAssociatedScopes( getUltimateType( ps[i] ), namespaces, classes ); + } + } + return; + } + + static private ICPPNamespaceScope getContainingNamespaceScope( IBinding binding ) throws DOMException{ + if( binding == null ) return null; + IScope scope = binding.getScope(); + while( scope != null && !(scope instanceof ICPPNamespaceScope) ){ + scope = scope.getParent(); + } + return (ICPPNamespaceScope) scope; + } + static private ICPPScope getLookupScope( IASTName name ) throws DOMException{ IASTNode parent = name.getParent(); @@ -452,10 +526,15 @@ public class CPPSemantics { return (ICPPScope) CPPVisitor.getContainingScope( name ); } - static private void lookup( CPPSemantics.LookupData data, IASTName name ) throws DOMException{ - IASTNode node = name; + static private void lookup( CPPSemantics.LookupData data, Object start ) throws DOMException{ + IASTNode node = data.astName; + + ICPPScope scope = null; + if( start instanceof ICPPScope ) + scope = (ICPPScope) start; + else + scope = getLookupScope( (IASTName) start ); - ICPPScope scope = getLookupScope( name ); while( scope != null ){ IASTNode blockItem = CPPVisitor.getContainingBlockItem( node ); if( scope.getPhysicalNode() != blockItem.getParent() && !(scope instanceof ICPPNamespaceScope) ) @@ -463,7 +542,7 @@ public class CPPSemantics { List directives = null; if( !data.usingDirectivesOnly ){ - IBinding binding = scope.getBinding( name ); + IBinding binding = scope.getBinding( data.astName ); if( binding == null ){ directives = new ArrayList(2); data.foundItems = lookupInScope( data, scope, blockItem, directives ); @@ -681,6 +760,11 @@ public class CPPSemantics { IASTName [] namespaceDefs = null; int namespaceIdx = -1; + if( data.associated.containsKey( scope ) ){ + //we are looking in scope, remove it from the associated scopes list + data.associated.remove( scope ); + } + List found = null; if( parent instanceof IASTCompoundStatement ){ @@ -1370,7 +1454,7 @@ public class CPPSemantics { //conversion operators if( s instanceof ICPPClassType ){ - char[] name = null;//TODO target.toCharArray(); + char[] name = EMPTY_NAME_ARRAY;//TODO target.toCharArray(); if( !CharArrayUtils.equals( name, EMPTY_NAME_ARRAY) ){ LookupData data = new LookupData( CharArrayUtils.concat( OPERATOR_, name )); @@ -1482,7 +1566,7 @@ public class CPPSemantics { t = ((ITypedef)t).getType(); else { if( t instanceof IPointerType ) - op1 = (IPointerType) t; + op2 = (IPointerType) t; break; } } @@ -1506,6 +1590,8 @@ public class CPPSemantics { break; } constInEveryCV2k &= op2.isConst(); + s = op1.getType(); + t = op2.getType(); } if( s instanceof IQualifierType ^ t instanceof IQualifierType ){ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java index 71d96bd864f..8eb2745a8ed 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java @@ -128,7 +128,6 @@ import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression; import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer; -import org.eclipse.cdt.internal.core.dom.parser.c.CPointerType; /** * @author aniefer @@ -1654,7 +1653,7 @@ public class CPPVisitor { return e.getProblem(); } } else if( op == IASTUnaryExpression.op_amper ){ - return new CPointerType( type ); + return new CPPPointerType( type ); } return type; }