1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00

Bug 300139: Content assist for qualified field access.

This commit is contained in:
Markus Schorn 2010-02-01 14:56:41 +00:00
parent 0afd9e1484
commit a009c11ad6
5 changed files with 113 additions and 71 deletions

View file

@ -191,4 +191,17 @@ public class BasicCompletionTest extends CompletionTestBase {
checkCompletion(code, true, expectedCpp); checkCompletion(code, true, expectedCpp);
checkCompletion(code, false, expectedC); checkCompletion(code, false, expectedC);
} }
// struct A{
// virtual void test() {}
// };
// struct B : A {
// void test() {}
// void func() {
// A::t
public void testQualifiedMemberAccess_Bug300139() throws Exception {
String code = getAboveComment();
String[] expectedCpp= {"test"};
checkCompletion(code, true, expectedCpp);
}
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others. * Copyright (c) 2004, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -18,6 +18,8 @@ import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; import org.eclipse.cdt.core.dom.ast.IASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNameOwner; import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
@ -25,11 +27,13 @@ import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
@ -38,6 +42,8 @@ import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Assert;
/** /**
@ -246,9 +252,9 @@ public class CPPASTQualifiedName extends CPPASTNameBase
IBinding binding = names[namesPos-1].resolveBinding(); IBinding binding = names[namesPos-1].resolveBinding();
if (binding instanceof ICPPClassType) { if (binding instanceof ICPPClassType) {
ICPPClassType classType = (ICPPClassType) binding; ICPPClassType classType = (ICPPClassType) binding;
if (!canBeFieldAccess(classType)) {
final boolean isDeclaration = getParent().getParent() instanceof IASTSimpleDeclaration; final boolean isDeclaration = getParent().getParent() instanceof IASTSimpleDeclaration;
List<IBinding> filtered = filterClassScopeBindings(classType, bindings, isDeclaration); List<IBinding> filtered = filterClassScopeBindings(classType, bindings, isDeclaration);
if (isDeclaration && nameMatches(classType.getNameCharArray(), if (isDeclaration && nameMatches(classType.getNameCharArray(),
n.getLookupKey(), isPrefix)) { n.getLookupKey(), isPrefix)) {
try { try {
@ -261,21 +267,43 @@ public class CPPASTQualifiedName extends CPPASTNameBase
} catch (DOMException e) { } catch (DOMException e) {
} }
} }
return filtered.toArray(new IBinding[filtered.size()]); return filtered.toArray(new IBinding[filtered.size()]);
} }
} }
}
return bindings; return bindings;
} }
private boolean canBeFieldAccess(ICPPClassType baseClass) {
IASTNode parent= getParent();
if (parent instanceof IASTFieldReference) {
return true;
}
if (parent instanceof IASTIdExpression) {
IScope scope= CPPVisitor.getContainingScope(this);
try {
while(scope != null) {
if (scope instanceof ICPPClassScope) {
ICPPClassType classType = ((ICPPClassScope) scope).getClassType();
if (SemanticUtil.calculateInheritanceDepth(classType, baseClass) >= 0) {
return true;
}
}
scope= scope.getParent();
}
} catch (DOMException e) {
}
}
return false;
}
private List<IBinding> filterClassScopeBindings(ICPPClassType classType, private List<IBinding> filterClassScopeBindings(ICPPClassType classType,
IBinding[] bindings, final boolean isDeclaration) { IBinding[] bindings, final boolean isDeclaration) {
List<IBinding> filtered = new ArrayList<IBinding>(); List<IBinding> filtered = new ArrayList<IBinding>();
try { try {
for (int i = 0; i < bindings.length; i++) { for (final IBinding binding : bindings) {
final IBinding binding = bindings[i];
if (binding instanceof IField) { if (binding instanceof IField) {
IField field = (IField) binding; IField field = (IField) binding;
if (!field.isStatic()) if (!field.isStatic())

View file

@ -2163,7 +2163,7 @@ public class CPPSemantics {
if (CPPTemplates.isDependentType(implicitType) || CPPTemplates.isDependentType(thisType)) { if (CPPTemplates.isDependentType(implicitType) || CPPTemplates.isDependentType(thisType)) {
IType s= getNestedType(thisType, TDEF|REF|CVTYPE); IType s= getNestedType(thisType, TDEF|REF|CVTYPE);
IType t= getNestedType(implicitType, TDEF|REF|CVTYPE); IType t= getNestedType(implicitType, TDEF|REF|CVTYPE);
if (Conversions.calculateInheritanceDepth(MAX_INHERITANCE_DEPTH, s, t) >= 0) if (SemanticUtil.calculateInheritanceDepth(s, t) >= 0)
return null; return null;
return CONTAINS_DEPENDENT_TYPES; return CONTAINS_DEPENDENT_TYPES;

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2004, 2009 IBM Corporation and others. * Copyright (c) 2004, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -24,7 +24,6 @@ import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IPointerType;
@ -33,7 +32,6 @@ import org.eclipse.cdt.core.dom.ast.IQualifierType;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@ -41,13 +39,11 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; 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.ICPPPointerToMemberType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion; import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
import org.eclipse.cdt.internal.core.dom.parser.Value; 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.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBinding;
@ -207,7 +203,7 @@ public class Conversions {
// [13.3.3.1-6] Derived to base conversion // [13.3.3.1-6] Derived to base conversion
if (uqsource instanceof ICPPClassType && uqtarget instanceof ICPPClassType) { if (uqsource instanceof ICPPClassType && uqtarget instanceof ICPPClassType) {
int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, uqsource, uqtarget); int depth= SemanticUtil.calculateInheritanceDepth(uqsource, uqtarget);
if (depth > -1) { if (depth > -1) {
if (depth == 0) { if (depth == 0) {
return new Cost(uqsource, uqtarget, Rank.IDENTITY); return new Cost(uqsource, uqtarget, Rank.IDENTITY);
@ -356,7 +352,7 @@ public class Conversions {
s= SemanticUtil.getNestedType(((IQualifierType) s).getType(), TDEF | REF); s= SemanticUtil.getNestedType(((IQualifierType) s).getType(), TDEF | REF);
if (t instanceof ICPPClassType && s instanceof ICPPClassType) { if (t instanceof ICPPClassType && s instanceof ICPPClassType) {
return calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, s, t); return SemanticUtil.calculateInheritanceDepth(s, t);
} }
} }
if (t == s || (t != null && s != null && t.isSameType(s))) { if (t == s || (t != null && s != null && t.isSameType(s))) {
@ -486,7 +482,7 @@ public class Conversions {
if (op != null && !(op instanceof IProblemBinding)) { if (op != null && !(op instanceof IProblemBinding)) {
final IType returnType = op.getType().getReturnType(); final IType returnType = op.getType().getReturnType();
final IType uqReturnType= getNestedType(returnType, REF | TDEF | CVTYPE); final IType uqReturnType= getNestedType(returnType, REF | TDEF | CVTYPE);
final int dist = calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, uqReturnType, t); final int dist = SemanticUtil.calculateInheritanceDepth(uqReturnType, t);
if (dist >= 0) { if (dist >= 0) {
final ICPPFunctionType ft = op.getType(); final ICPPFunctionType ft = op.getType();
IType implicitType= CPPSemantics.getImplicitType(op, ft.isConst(), ft.isVolatile()); IType implicitType= CPPSemantics.getImplicitType(op, ft.isConst(), ft.isVolatile());
@ -557,49 +553,6 @@ public class Conversions {
return null; return null;
} }
/**
* Calculates the number of edges in the inheritance path of <code>clazz</code> to
* <code>ancestorToFind</code>, returning -1 if no inheritance relationship is found.
* @param clazz the class to search upwards from
* @param ancestorToFind the class to find in the inheritance graph
* @return the number of edges in the inheritance graph, or -1 if the specified classes have
* no inheritance relation
* @throws DOMException
*/
static final int calculateInheritanceDepth(int maxdepth, IType type, IType ancestorToFind)
throws DOMException {
if (type == ancestorToFind || type.isSameType(ancestorToFind)) {
return 0;
}
if (maxdepth > 0 && type instanceof ICPPClassType && ancestorToFind instanceof ICPPClassType) {
ICPPClassType clazz = (ICPPClassType) type;
if (clazz instanceof ICPPDeferredClassInstance) {
clazz= (ICPPClassType) ((ICPPDeferredClassInstance) clazz).getSpecializedBinding();
}
for (ICPPBase cppBase : clazz.getBases()) {
IBinding base= cppBase.getBaseClass();
if (base instanceof IType) {
IType tbase= (IType) base;
if (tbase.isSameType(ancestorToFind) ||
(ancestorToFind instanceof ICPPSpecialization && // allow some flexibility with templates
((IType)((ICPPSpecialization) ancestorToFind).getSpecializedBinding()).isSameType(tbase))) {
return 1;
}
if (tbase instanceof ICPPClassType) {
int n= calculateInheritanceDepth(maxdepth - 1, tbase, ancestorToFind);
if (n > 0)
return n + 1;
}
}
}
}
return -1;
}
/** /**
* Attempts the conversions below and returns whether this completely converts the source to * Attempts the conversions below and returns whether this completely converts the source to
* the target type. * the target type.
@ -872,7 +825,7 @@ public class Conversions {
// to an rvalue of type "pointer to cv B", where B is a base class of D. // to an rvalue of type "pointer to cv B", where B is a base class of D.
IType srcPtrTgt= getNestedType(srcPtr.getType(), TDEF | CVTYPE | REF); IType srcPtrTgt= getNestedType(srcPtr.getType(), TDEF | CVTYPE | REF);
if (tgtPtrTgt instanceof ICPPClassType && srcPtrTgt instanceof ICPPClassType) { if (tgtPtrTgt instanceof ICPPClassType && srcPtrTgt instanceof ICPPClassType) {
int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, srcPtrTgt, tgtPtrTgt); int depth= SemanticUtil.calculateInheritanceDepth(srcPtrTgt, tgtPtrTgt);
if (depth == -1) { if (depth == -1) {
cost.setRank(Rank.NO_MATCH); cost.setRank(Rank.NO_MATCH);
return true; return true;
@ -896,8 +849,8 @@ public class Conversions {
IType st = spm.getType(); IType st = spm.getType();
IType tt = tpm.getType(); IType tt = tpm.getType();
if (st != null && tt != null && st.isSameType(tt)) { if (st != null && tt != null && st.isSameType(tt)) {
int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, int depth = SemanticUtil.calculateInheritanceDepth(tpm.getMemberOfClass(),
tpm.getMemberOfClass(), spm.getMemberOfClass()); spm.getMemberOfClass());
if (depth == -1) { if (depth == -1) {
cost.setRank(Rank.NO_MATCH); cost.setRank(Rank.NO_MATCH);
return true; return true;

View file

@ -36,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; 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.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.Keywords;
@ -538,4 +539,51 @@ public class SemanticUtil {
} }
return false; return false;
} }
/**
* Calculates the number of edges in the inheritance path of <code>type</code> to
* <code>ancestorToFind</code>, returning -1 if no inheritance relationship is found.
* @param type the class to search upwards from
* @param baseClass the class to find in the inheritance graph
* @return the number of edges in the inheritance graph, or -1 if the specified classes have
* no inheritance relation
* @throws DOMException
*/
public static final int calculateInheritanceDepth(IType type, IType baseClass) throws DOMException {
return calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, type, baseClass);
}
private static final int calculateInheritanceDepth(int maxdepth, IType type, IType baseClass)
throws DOMException {
if (type == baseClass || type.isSameType(baseClass)) {
return 0;
}
if (maxdepth > 0 && type instanceof ICPPClassType && baseClass instanceof ICPPClassType) {
ICPPClassType clazz = (ICPPClassType) type;
if (clazz instanceof ICPPDeferredClassInstance) {
clazz= (ICPPClassType) ((ICPPDeferredClassInstance) clazz).getSpecializedBinding();
}
for (ICPPBase cppBase : clazz.getBases()) {
IBinding base= cppBase.getBaseClass();
if (base instanceof IType) {
IType tbase= (IType) base;
if (tbase.isSameType(baseClass) ||
(baseClass instanceof ICPPSpecialization && // allow some flexibility with templates
((IType)((ICPPSpecialization) baseClass).getSpecializedBinding()).isSameType(tbase))) {
return 1;
}
if (tbase instanceof ICPPClassType) {
int n= calculateInheritanceDepth(maxdepth - 1, tbase, baseClass);
if (n > 0)
return n + 1;
}
}
}
}
return -1;
}
} }