mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-19 15:05:36 +02:00
Resolution for dependent names, bug 265926.
This commit is contained in:
parent
10042ec8df
commit
35f45ec13f
5 changed files with 143 additions and 17 deletions
|
@ -3897,7 +3897,7 @@ public class AST2TemplateTests extends AST2BaseTest {
|
|||
// g(t);
|
||||
// }
|
||||
// template <typename T> 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 <typename T> class XT {
|
||||
// void m();
|
||||
// C* ptr() {return 0;}
|
||||
// };
|
||||
//
|
||||
// template <typename T> void XT<T>::m() {
|
||||
// c(this)->a();
|
||||
// ptr()->a();
|
||||
// };
|
||||
//
|
||||
// class C {
|
||||
// void a() {};
|
||||
// };
|
||||
public void testDependentNameReferencingLaterDeclaration_265926b() throws Exception {
|
||||
final String code = getAboveComment();
|
||||
parseAndCheckBindings(code, ParserLanguage.CPP);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue