mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 01:36:01 +02:00
Bug 300139: Content assist for qualified field access.
This commit is contained in:
parent
0afd9e1484
commit
a009c11ad6
5 changed files with 113 additions and 71 deletions
|
@ -191,4 +191,17 @@ public class BasicCompletionTest extends CompletionTestBase {
|
|||
checkCompletion(code, true, expectedCpp);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* 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.DOMException;
|
||||
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.IASTNameOwner;
|
||||
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.IEnumerator;
|
||||
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.cpp.ICPPASTConversionName;
|
||||
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.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.ICPPConstructor;
|
||||
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.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.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
|
||||
/**
|
||||
|
@ -246,36 +252,58 @@ public class CPPASTQualifiedName extends CPPASTNameBase
|
|||
IBinding binding = names[namesPos-1].resolveBinding();
|
||||
if (binding instanceof ICPPClassType) {
|
||||
ICPPClassType classType = (ICPPClassType) binding;
|
||||
final boolean isDeclaration = getParent().getParent() instanceof IASTSimpleDeclaration;
|
||||
List<IBinding> filtered = filterClassScopeBindings(classType, bindings, isDeclaration);
|
||||
|
||||
if (isDeclaration && nameMatches(classType.getNameCharArray(),
|
||||
n.getLookupKey(), isPrefix)) {
|
||||
try {
|
||||
ICPPConstructor[] constructors = classType.getConstructors();
|
||||
for (int i = 0; i < constructors.length; i++) {
|
||||
if (!constructors[i].isImplicit()) {
|
||||
filtered.add(constructors[i]);
|
||||
if (!canBeFieldAccess(classType)) {
|
||||
final boolean isDeclaration = getParent().getParent() instanceof IASTSimpleDeclaration;
|
||||
List<IBinding> filtered = filterClassScopeBindings(classType, bindings, isDeclaration);
|
||||
if (isDeclaration && nameMatches(classType.getNameCharArray(),
|
||||
n.getLookupKey(), isPrefix)) {
|
||||
try {
|
||||
ICPPConstructor[] constructors = classType.getConstructors();
|
||||
for (int i = 0; i < constructors.length; i++) {
|
||||
if (!constructors[i].isImplicit()) {
|
||||
filtered.add(constructors[i]);
|
||||
}
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
return filtered.toArray(new IBinding[filtered.size()]);
|
||||
}
|
||||
|
||||
return filtered.toArray(new IBinding[filtered.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
IBinding[] bindings, final boolean isDeclaration) {
|
||||
List<IBinding> filtered = new ArrayList<IBinding>();
|
||||
|
||||
try {
|
||||
for (int i = 0; i < bindings.length; i++) {
|
||||
final IBinding binding = bindings[i];
|
||||
for (final IBinding binding : bindings) {
|
||||
if (binding instanceof IField) {
|
||||
IField field = (IField) binding;
|
||||
if (!field.isStatic())
|
||||
|
|
|
@ -2163,7 +2163,7 @@ public class CPPSemantics {
|
|||
if (CPPTemplates.isDependentType(implicitType) || CPPTemplates.isDependentType(thisType)) {
|
||||
IType s= getNestedType(thisType, 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 CONTAINS_DEPENDENT_TYPES;
|
||||
|
|
|
@ -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
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* 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.IArrayType;
|
||||
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.IFunctionType;
|
||||
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.IValue;
|
||||
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.ICPPClassType;
|
||||
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.ICPPPointerToMemberType;
|
||||
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.Value;
|
||||
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.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.ReferenceBinding;
|
||||
|
||||
|
@ -207,7 +203,7 @@ public class Conversions {
|
|||
|
||||
// [13.3.3.1-6] Derived to base conversion
|
||||
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 == 0) {
|
||||
return new Cost(uqsource, uqtarget, Rank.IDENTITY);
|
||||
|
@ -356,7 +352,7 @@ public class Conversions {
|
|||
s= SemanticUtil.getNestedType(((IQualifierType) s).getType(), TDEF | REF);
|
||||
|
||||
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))) {
|
||||
|
@ -486,7 +482,7 @@ public class Conversions {
|
|||
if (op != null && !(op instanceof IProblemBinding)) {
|
||||
final IType returnType = op.getType().getReturnType();
|
||||
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) {
|
||||
final ICPPFunctionType ft = op.getType();
|
||||
IType implicitType= CPPSemantics.getImplicitType(op, ft.isConst(), ft.isVolatile());
|
||||
|
@ -557,49 +553,6 @@ public class Conversions {
|
|||
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
|
||||
* 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.
|
||||
IType srcPtrTgt= getNestedType(srcPtr.getType(), TDEF | CVTYPE | REF);
|
||||
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) {
|
||||
cost.setRank(Rank.NO_MATCH);
|
||||
return true;
|
||||
|
@ -896,8 +849,8 @@ public class Conversions {
|
|||
IType st = spm.getType();
|
||||
IType tt = tpm.getType();
|
||||
if (st != null && tt != null && st.isSameType(tt)) {
|
||||
int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH,
|
||||
tpm.getMemberOfClass(), spm.getMemberOfClass());
|
||||
int depth = SemanticUtil.calculateInheritanceDepth(tpm.getMemberOfClass(),
|
||||
spm.getMemberOfClass());
|
||||
if (depth == -1) {
|
||||
cost.setRank(Rank.NO_MATCH);
|
||||
return true;
|
||||
|
|
|
@ -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.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.ICPPTemplateArgument;
|
||||
import org.eclipse.cdt.core.index.IIndexBinding;
|
||||
import org.eclipse.cdt.core.parser.Keywords;
|
||||
|
@ -538,4 +539,51 @@ public class SemanticUtil {
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue