From 4ae93462896d157fd14f4a0068339068b4e03a9b Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Mon, 10 Mar 2008 16:27:45 +0000 Subject: [PATCH] Name resolution for qualified member declarations, bug 222026. --- .../core/parser/tests/ast2/AST2CPPTests.java | 97 +++++++++++++++++++ .../core/dom/parser/cpp/CPPClassScope.java | 19 +++- .../core/dom/parser/cpp/CPPFunction.java | 2 +- .../core/dom/parser/cpp/CPPMethod.java | 31 ++---- .../core/dom/parser/cpp/CPPScope.java | 22 ++++- .../core/dom/parser/cpp/CPPSemantics.java | 35 ++++--- .../core/dom/parser/cpp/CPPVisitor.java | 19 ++-- .../dom/rewrite/changegenerator/Messages.java | 3 +- .../composite/cpp/TemplateInstanceUtil.java | 9 +- 9 files changed, 176 insertions(+), 61 deletions(-) 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 e17c1801a1a..84a68367f2a 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 @@ -5729,4 +5729,101 @@ public class AST2CPPTests extends AST2BaseTest { bh.assertNonProblem("func(qualified)", 4); bh.assertNonProblem("func(unqualified)", 4); } + + + // class Test { + // void Test::member1(); + // void Test::member2() {}; + // }; + // void Test::member1(){ + // member2(); + // } + public void testQualifiedMemberDeclaration_Bug222026() throws Exception { + final String code = getContents(1)[0].toString(); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + + IBinding b= bh.assertNonProblem("member1", 7); + IBinding b2= bh.assertNonProblem("member1(){", 7); + assertTrue(b instanceof ICPPMethod); + ICPPMethod m1= (ICPPMethod) b; + assertEquals("member1", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + + bh= new BindingAssertionHelper(code, true); + b= bh.assertNonProblem("member2", 7); + b2= bh.assertNonProblem("member2();", 7); + assertTrue(b instanceof ICPPMethod); + m1= (ICPPMethod) b; + assertEquals("member2", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + + // different resolution order + bh= new BindingAssertionHelper(code, true); + b2= bh.assertNonProblem("member1(){", 7); + b= bh.assertNonProblem("member1", 7); + assertTrue(b instanceof ICPPMethod); + m1= (ICPPMethod) b; + assertEquals("member1", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + + bh= new BindingAssertionHelper(code, true); + b2= bh.assertNonProblem("member2();", 7); + b= bh.assertNonProblem("member2", 7); + assertTrue(b instanceof ICPPMethod); + m1= (ICPPMethod) b; + assertEquals("member2", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + } + + // namespace Test { + // void Test::member1(); + // void Test::member2() {}; + // } + // void Test::member1(){ + // member2(); + // } + public void testQualifiedMemberDeclarationInNamespace_Bug222026() throws Exception { + final String code = getContents(1)[0].toString(); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + + IBinding b= bh.assertNonProblem("member1", 7); + IBinding b2= bh.assertNonProblem("member1(){", 7); + assertTrue(b instanceof ICPPFunction); + ICPPFunction m1= (ICPPFunction) b; + assertEquals("member1", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + + bh= new BindingAssertionHelper(code, true); + b= bh.assertNonProblem("member2", 7); + b2= bh.assertNonProblem("member2();", 7); + assertTrue(b instanceof ICPPFunction); + m1= (ICPPFunction) b; + assertEquals("member2", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + + // different resolution order + bh= new BindingAssertionHelper(code, true); + b2= bh.assertNonProblem("member1(){", 7); + b= bh.assertNonProblem("member1", 7); + assertTrue(b instanceof ICPPFunction); + m1= (ICPPFunction) b; + assertEquals("member1", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + + bh= new BindingAssertionHelper(code, true); + b2= bh.assertNonProblem("member2();", 7); + b= bh.assertNonProblem("member2", 7); + assertTrue(b instanceof ICPPFunction); + m1= (ICPPFunction) b; + assertEquals("member2", m1.getName()); + assertEquals("Test", m1.getScope().getScopeName().toString()); + assertSame(b, b2); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java index 051fc783f89..1d9cb3bbefe 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java @@ -134,6 +134,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { } } + @Override public IScope getParent() { ICPPASTCompositeTypeSpecifier compType = (ICPPASTCompositeTypeSpecifier) getPhysicalNode(); IASTName compName = compType.getName(); @@ -147,6 +148,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPScope#addBinding(org.eclipse.cdt.core.dom.ast.IBinding) */ + @Override public void addBinding(IBinding binding) { if (binding instanceof ICPPConstructor) { addConstructor(binding); @@ -155,11 +157,16 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { super.addBinding(binding); } - public void addName(IASTName name) { - if (name instanceof ICPPASTQualifiedName) - return; - + @Override + public void addName(IASTName name) throws DOMException { IASTNode parent = name.getParent(); + if (name instanceof ICPPASTQualifiedName) { + final IASTName[] qn= ((ICPPASTQualifiedName) name).getNames(); + final IASTName ln= qn[qn.length-1]; + if (CPPVisitor.getContainingScope(name) != CPPVisitor.getContainingScope(ln)) { + return; + } + } if (parent instanceof IASTDeclarator) { if (CPPVisitor.isConstructor(this, (IASTDeclarator) parent)) { addConstructor(name); @@ -194,6 +201,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPScope#getBinding(int, char[]) */ + @Override public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet fileSet) throws DOMException { char[] c = name.toCharArray(); @@ -213,6 +221,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { return super.getBinding(name, resolve, fileSet); } + @Override public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) throws DOMException { char[] c = name.toCharArray(); @@ -298,6 +307,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IScope#find(java.lang.String) */ + @Override public IBinding[] find(String name) throws DOMException { char[] n = name.toCharArray(); ICPPASTCompositeTypeSpecifier compType = (ICPPASTCompositeTypeSpecifier) getPhysicalNode(); @@ -370,6 +380,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope { /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPScope#removeBinding(org.eclipse.cdt.core.dom.ast.IBinding) */ + @Override public void removeBinding(IBinding binding) { if (binding instanceof ICPPConstructor) { removeBinding(CONSTRUCTOR_KEY, binding); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java index 1f121e773d1..58ddb02b4f0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java @@ -259,7 +259,7 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt return getASTName().toCharArray(); } - private IASTName getASTName() { + protected IASTName getASTName() { IASTDeclarator dtor = (definition != null) ? definition : declarations[0]; IASTDeclarator nested= dtor.getNestedDeclarator(); while (nested != null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPMethod.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPMethod.java index 1c28193542e..50917c10da9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPMethod.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPMethod.java @@ -176,32 +176,13 @@ public class CPPMethod extends CPPFunction implements ICPPMethod { } @Override - public String getName() { - if( definition != null ){ - IASTName n = definition.getName(); - if( n instanceof ICPPASTQualifiedName ){ - IASTName [] ns = ((ICPPASTQualifiedName)n).getNames(); - return ns[ ns.length - 1 ].toString(); - } - return n.toString(); + protected IASTName getASTName() { + IASTName name= definition != null ? definition.getName() : declarations[0].getName(); + if( name instanceof ICPPASTQualifiedName ){ + final IASTName[] ns = ((ICPPASTQualifiedName)name).getNames(); + return ns[ns.length - 1]; } - return declarations[0].getName().toString(); - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.core.dom.ast.IBinding#getNameCharArray() - */ - @Override - public char[] getNameCharArray() { - if( definition != null ){ - IASTName n = definition.getName(); - if( n instanceof ICPPASTQualifiedName ){ - IASTName [] ns = ((ICPPASTQualifiedName)n).getNames(); - return ns[ ns.length - 1 ].toCharArray(); - } - return n.toCharArray(); - } - return declarations[0].getName().toCharArray(); + return name; } /* (non-Javadoc) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java index 15317c45185..4ca56538139 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java @@ -23,6 +23,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; @@ -73,14 +74,25 @@ abstract public class CPPScope implements ICPPScope, IASTInternalScope { protected CharArrayObjectMap bindings = null; - public void addName(IASTName name) { + public void addName(IASTName name) throws DOMException { if( bindings == null ) bindings = new CharArrayObjectMap(1); - if( name instanceof ICPPASTQualifiedName ){ - //name belongs to a different scope, don't add it here - return; + char[] c; + if (name instanceof ICPPASTQualifiedName) { + if (physicalNode instanceof ICPPASTCompositeTypeSpecifier == false && + physicalNode instanceof ICPPASTNamespaceDefinition == false) + return; + + //name belongs to a different scope, don't add it here except it names this scope + final IASTName[] ns= ((ICPPASTQualifiedName) name).getNames(); + final IASTName ln= ns[ns.length-1]; + if (CPPVisitor.getContainingScope(name) != CPPVisitor.getContainingScope(ln)) + return; + c= ln.toCharArray(); + } + else { + c= name.toCharArray(); } - char [] c = name.toCharArray(); Object o = bindings.get( c ); if( o != null ){ if( o instanceof ObjectSet ){ 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 6a6b9232448..d0090ecb2fc 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 @@ -1485,7 +1485,7 @@ public class CPPSemantics { //9-2 a class name is also inserted into the scope of the class itself IASTName n = comp.getName(); - if( nameMatches( data, n ) ) { + if( nameMatches( data, n, scope) ) { found = (IASTName[]) ArrayUtil.append( IASTName.class, found, n ); } } else if ( parent instanceof ICPPASTNamespaceDefinition ){ @@ -1716,14 +1716,14 @@ public class CPPSemantics { dtor = dtor.getNestedDeclarator(); IASTName declName = dtor.getName(); ASTInternal.addName( scope, declName ); - if( !data.typesOnly && nameMatches( data, declName ) ) { + if( !data.typesOnly && nameMatches( data, declName, scope ) ) { return declName; } } } else if( node instanceof ICPPASTTemplateParameter ){ IASTName name = CPPTemplates.getTemplateParameterName( (ICPPASTTemplateParameter) node ); ASTInternal.addName( scope, name ); - if( nameMatches( data, name ) ) { + if( nameMatches( data, name, scope ) ) { return name; } } @@ -1742,7 +1742,7 @@ public class CPPSemantics { IASTName declaratorName = declarator.getName(); ASTInternal.addName( scope, declaratorName ); if( !data.typesOnly || simpleDeclaration.getDeclSpecifier().getStorageClass() == IASTDeclSpecifier.sc_typedef ) { - if( nameMatches( data, declaratorName ) ) { + if( nameMatches( data, declaratorName, scope ) ) { if( resultName == null ) resultName = declaratorName; else if( resultArray == null ) @@ -1805,7 +1805,7 @@ public class CPPSemantics { if( enumerator == null ) break; tempName = enumerator.getName(); ASTInternal.addName( scope, tempName ); - if( !data.typesOnly && nameMatches( data, tempName ) ) { + if( !data.typesOnly && nameMatches( data, tempName, scope ) ) { if( resultName == null ) resultName = tempName; else if( resultArray == null ) @@ -1817,7 +1817,7 @@ public class CPPSemantics { } if( specName != null ) { ASTInternal.addName( scope, specName ); - if( nameMatches( data, specName ) ) { + if( nameMatches( data, specName, scope ) ) { if( resultName == null ) resultName = specName; else if( resultArray == null ) @@ -1834,18 +1834,18 @@ public class CPPSemantics { name = ns[ ns.length - 1 ]; } ASTInternal.addName( scope, name ); - if( nameMatches( data, name ) ) { + if( nameMatches( data, name, scope ) ) { return name; } } else if( declaration instanceof ICPPASTNamespaceDefinition ){ IASTName namespaceName = ((ICPPASTNamespaceDefinition) declaration).getName(); ASTInternal.addName( scope, namespaceName ); - if( nameMatches( data, namespaceName ) ) + if( nameMatches( data, namespaceName, scope ) ) return namespaceName; } else if( declaration instanceof ICPPASTNamespaceAlias ){ IASTName alias = ((ICPPASTNamespaceAlias) declaration).getAlias(); ASTInternal.addName( scope, alias ); - if( nameMatches( data, alias ) ) + if( nameMatches( data, alias, scope ) ) return alias; } else if( declaration instanceof IASTFunctionDefinition ){ IASTFunctionDefinition functionDef = (IASTFunctionDefinition) declaration; @@ -1856,7 +1856,7 @@ public class CPPSemantics { IASTName declName = declarator.getName(); ASTInternal.addName( scope, declName ); - if( !data.typesOnly && nameMatches( data, declName ) ) { + if( !data.typesOnly && nameMatches( data, declName, scope ) ) { return declName; } } @@ -1867,11 +1867,20 @@ public class CPPSemantics { return resultName; } - private static final boolean nameMatches( LookupData data, IASTName potential ){ + private static final boolean nameMatches( LookupData data, IASTName potential, IScope scope) throws DOMException{ if( potential instanceof ICPPASTQualifiedName ){ + IASTNode phn= ASTInternal.getPhysicalNodeOfScope(scope); + if (phn instanceof ICPPASTCompositeTypeSpecifier == false && phn instanceof ICPPASTNamespaceDefinition == false) + return false; + //A qualified name implies the name actually belongs to a different scope, and should - //not be considered here. - return false; + //not be considered here, except the qualifier names the scope itself + final IASTName[] qn= ((ICPPASTQualifiedName) potential).getNames(); + final IASTName ln= qn[qn.length-1]; + if (CPPVisitor.getContainingScope(ln) != scope) + return false; + + potential= ln; } char[] c = potential.toCharArray(); char [] n = data.name(); 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 3c1ff4be251..b912efc2bae 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 @@ -167,16 +167,21 @@ public class CPPVisitor { if( binding instanceof IProblemBinding && parent instanceof ICPPASTQualifiedName && !(parent.getParent() instanceof ICPPASTNamespaceAlias)) { - if( ((IProblemBinding)binding).getID() == IProblemBinding.SEMANTIC_MEMBER_DECLARATION_NOT_FOUND ){ + final ICPPASTQualifiedName qname= (ICPPASTQualifiedName)parent; + final IASTName[] ns= qname.getNames(); + if (ns[ns.length-1] != name) + return binding; + + parent = parent.getParent(); + if( ((IProblemBinding)binding).getID() == IProblemBinding.SEMANTIC_MEMBER_DECLARATION_NOT_FOUND ){ IASTNode node = getContainingBlockItem( name.getParent() ); - if( node.getPropertyInParent() != IASTCompositeTypeSpecifier.MEMBER_DECLARATION ) + ASTNodeProperty prop= node.getPropertyInParent(); + if (prop != IASTCompositeTypeSpecifier.MEMBER_DECLARATION && prop != ICPPASTNamespaceDefinition.OWNED_DECLARATION) return binding; + + if (getContainingScope(qname) != getContainingScope(name)) + return binding; } - IASTName [] ns = ((ICPPASTQualifiedName)parent).getNames(); - if( ns[ ns.length - 1 ] == name ) - parent = parent.getParent(); - else - return binding; } else { return binding; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/Messages.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/Messages.java index b85600d1d49..b082183a05d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/Messages.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/Messages.java @@ -13,8 +13,7 @@ package org.eclipse.cdt.internal.core.dom.rewrite.changegenerator; import org.eclipse.osgi.util.NLS; /** - * mstodo - * + * External strings for the change generator. * @since 5.0 */ public class Messages extends NLS { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java index a5fa03da8de..54091f96122 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java @@ -1,13 +1,13 @@ /******************************************************************************* - * Copyright (c) 2007 Symbian Software Systems and others. + * Copyright (c) 2007, 2008 Symbian Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Andrew Ferguson (Symbian) - Initial implementation - * Bryan Wilkinson (QNX) + * Andrew Ferguson (Symbian) - Initial implementation + * Bryan Wilkinson (QNX) *******************************************************************************/ package org.eclipse.cdt.internal.core.index.composite.cpp; @@ -44,7 +44,8 @@ public class TemplateInstanceUtil { if(specd instanceof ICPPTemplateDefinition) { keysToAdapt= ((ICPPTemplateDefinition)specd).getTemplateParameters(); } - for(int i=0; i