diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 3aebcb7f55e..2e3ce6aadd2 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -3897,7 +3897,7 @@ public class AST2TemplateTests extends AST2BaseTest { // g(t); // } // template void g(T t) {} - public void testDependentNameReferencingLaterDeclaration_265926() throws Exception { + public void testDependentNameReferencingLaterDeclaration_265926a() throws Exception { final String code = getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); IFunction gref= bh.assertNonProblem("g(t)", 1); @@ -3906,4 +3906,25 @@ public class AST2TemplateTests extends AST2BaseTest { parseAndCheckBindings(code, ParserLanguage.CPP); } + + // class C; + // C* c(void*) {return 0;} + // + // template class XT { + // void m(); + // C* ptr() {return 0;} + // }; + // + // template void XT::m() { + // c(this)->a(); + // ptr()->a(); + // }; + // + // class C { + // void a() {}; + // }; + public void testDependentNameReferencingLaterDeclaration_265926b() throws Exception { + final String code = getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 54fd01ee445..ec2680d1789 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Set; import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.EScopeKind; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; @@ -46,6 +47,7 @@ import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression; import org.eclipse.cdt.core.dom.ast.IASTLabelStatement; +import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNameOwner; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; @@ -56,6 +58,8 @@ import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; +import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBinding; @@ -88,6 +92,7 @@ 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.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; @@ -569,7 +574,7 @@ public class CPPSemantics { return (ICPPNamespaceScope) scope; } - static private ICPPScope getLookupScope(IASTName name) throws DOMException { + static private ICPPScope getLookupScope(IASTName name, LookupData data) throws DOMException { IASTNode parent = name.getParent(); IScope scope = null; if (parent instanceof ICPPASTBaseSpecifier) { @@ -586,7 +591,7 @@ public class CPPSemantics { if (!(binding instanceof IProblemBinding)) scope = binding.getScope(); } else { - scope = CPPVisitor.getContainingScope(name); + scope = CPPVisitor.getContainingScope(name, data); } if (scope instanceof ICPPScope) { return (ICPPScope)scope; @@ -688,15 +693,14 @@ public class CPPSemantics { */ static protected void lookup(LookupData data, Object start) throws DOMException { final IIndexFileSet fileSet= getIndexFileSet(data); - IASTNode blockItem= data.astName; - if (blockItem == null) + if (data.astName == null) return; ICPPScope nextScope= null; if (start instanceof ICPPScope) { nextScope= (ICPPScope) start; } else if (start instanceof IASTName) { - nextScope= getLookupScope((IASTName) start); + nextScope= getLookupScope((IASTName) start, data); } if (nextScope == null) return; @@ -717,6 +721,12 @@ public class CPPSemantics { } else { nextTmplScope= enclosingTemplateScope(data.astName); } + if (!data.usesEnclosingScope && nextTmplScope != null) { + nextTmplScope= null; + if (dependsOnTemplateFieldReference(data.astName)) { + data.checkPointOfDecl= false; + } + } while (nextScope != null || nextTmplScope != null) { // when the non-template scope is no longer contained within the first template scope, @@ -735,7 +745,6 @@ public class CPPSemantics { if (scope instanceof IIndexScope && data.tu != null) { scope= (ICPPScope) data.tu.mapToASTScope(((IIndexScope) scope)); } - blockItem = CPPVisitor.getContainingBlockItem(blockItem); if (!data.usingDirectivesOnly) { IBinding[] bindings= getBindingsFromScope(scope, fileSet, data); @@ -800,7 +809,95 @@ public class CPPSemantics { } } - private static IBinding[] getBindingsFromScope(ICPPScope scope, final IIndexFileSet fileSet, LookupData data) throws DOMException { + /** + * Checks whether the name directly or indirectly depends on the this pointer. + */ + private static boolean dependsOnTemplateFieldReference(IASTName astName) { + if (astName.getPropertyInParent() != IASTFieldReference.FIELD_NAME) + return false; + + final boolean[] result= {false}; + final IASTExpression fieldOwner = ((IASTFieldReference)astName.getParent()).getFieldOwner(); + fieldOwner.accept(new ASTVisitor(){ + { + shouldVisitNames= true; + shouldVisitExpressions= true; + } + + @Override + public int visit(IASTName name) { + IBinding b= name.resolvePreBinding(); + if (b instanceof ICPPUnknownBinding || b instanceof ICPPTemplateDefinition) { + result[0]= true; + return PROCESS_ABORT; + } + if (b instanceof ICPPMember) { + ICPPMember mem= (ICPPMember) b; + try { + if (!mem.isStatic()) { + ICPPClassType owner= mem.getClassOwner(); + if (owner instanceof ICPPUnknownBinding || owner instanceof ICPPTemplateDefinition) { + result[0]= true; + return PROCESS_ABORT; + } + } + } catch (DOMException e) { + } + } + if (name instanceof ICPPASTTemplateId) + return PROCESS_SKIP; + return PROCESS_CONTINUE; + } + + @Override + public int visit(IASTExpression expression) { + if (expression instanceof IASTLiteralExpression) { + if (((IASTLiteralExpression) expression).getKind() == IASTLiteralExpression.lk_this) { + final IType thisType = SemanticUtil.getNestedType(expression.getExpressionType(), TDEF | CVQ | PTR | ARRAY | MPTR | REF); + if (thisType instanceof ICPPUnknownBinding || thisType instanceof ICPPTemplateDefinition) { + result[0]= true; + return PROCESS_ABORT; + } + } + } + if (expression instanceof IASTUnaryExpression) { + switch (((IASTUnaryExpression) expression).getOperator()) { + case IASTUnaryExpression.op_sizeof: + case IASTUnaryExpression.op_typeid: + case IASTUnaryExpression.op_throw: + return PROCESS_SKIP; + } + } else if (expression instanceof IASTTypeIdExpression) { + switch (((IASTTypeIdExpression) expression).getOperator()) { + case IASTTypeIdExpression.op_sizeof: + case IASTTypeIdExpression.op_typeid: + return PROCESS_SKIP; + } + } else if (expression instanceof IASTCastExpression) { + if (!((IASTCastExpression) expression).getTypeId().accept(this)) { + return PROCESS_ABORT; + } + return PROCESS_SKIP; + } else if (expression instanceof ICPPASTNewExpression) { + if (!((ICPPASTNewExpression) expression).getTypeId().accept(this)) { + return PROCESS_ABORT; + } + return PROCESS_SKIP; + } else if (expression instanceof ICPPASTSimpleTypeConstructorExpression) { + return PROCESS_SKIP; + } else if (expression instanceof IASTTypeIdInitializerExpression) { + if (!((IASTTypeIdInitializerExpression) expression).getTypeId().accept(this)) { + return PROCESS_ABORT; + } + return PROCESS_SKIP; + } + return PROCESS_CONTINUE; + } + }); + return result[0]; + } + + private static IBinding[] getBindingsFromScope(ICPPScope scope, final IIndexFileSet fileSet, LookupData data) throws DOMException { IBinding[] bindings; if (scope instanceof ICPPASTInternalScope) { bindings= ((ICPPASTInternalScope) scope).getBindings(data.astName, true, data.prefixLookup, fileSet, data.checkPointOfDecl); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index d7780cabffc..981ffcd3bdc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -890,7 +890,11 @@ public class CPPVisitor extends ASTQueries { } public static IScope getContainingScope(IASTName name) { - IScope scope= getContainingScopeOrNull(name); + return getContainingScope(name, null); + } + + public static IScope getContainingScope(IASTName name, LookupData data) { + IScope scope= getContainingScopeOrNull(name, data); if (scope == null) { return new CPPScope.CPPScopeProblem(name, IProblemBinding.SEMANTIC_BAD_SCOPE); } @@ -898,7 +902,7 @@ public class CPPVisitor extends ASTQueries { return scope; } - private static IScope getContainingScopeOrNull(IASTName name) { + private static IScope getContainingScopeOrNull(IASTName name, LookupData data) { if (name == null) { return null; } @@ -922,6 +926,9 @@ public class CPPVisitor extends ASTQueries { } } if (i > 0) { + if (data != null) { + data.usesEnclosingScope= false; + } IBinding binding = names[i - 1].resolveBinding(); while (binding instanceof ITypedef) { IType t = ((ITypedef) binding).getType(); @@ -954,6 +961,9 @@ public class CPPVisitor extends ASTQueries { } } } else if (parent instanceof ICPPASTFieldReference) { + if (data != null) { + data.usesEnclosingScope= false; + } final ICPPASTFieldReference fieldReference = (ICPPASTFieldReference) parent; IType type = CPPSemantics.getChainedMemberAccessOperatorReturnType(fieldReference); if (fieldReference.isPointerDereference()) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index ccf69648fee..6f7c9f14581 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -14,13 +14,7 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVQ; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.PTR_CVQ; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.addQualifiers; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateType; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.DOMException; @@ -43,6 +37,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; @@ -805,6 +800,8 @@ public class Conversions { */ private static final boolean isCompleteType(IType type) { type= getUltimateType(type, false); + if (type instanceof ICPPTemplateInstance) + return true; if (type instanceof ICPPClassType) { if (type instanceof IIndexFragmentBinding) { try { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java index 8430f515507..3b82153587c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java @@ -101,6 +101,7 @@ public class LookupData { public boolean typesOnly = false; public boolean considerConstructors = false; public boolean checkPointOfDecl= true; // for lookup of unknown bindings the point of declaration can be reversed. + public boolean usesEnclosingScope= true; // for field references or qualified names, enclosing template declarations are ignored. public ICPPClassType skippedScope; public Object foundItems = null;