1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-14 03:35:37 +02:00

Bug 402617 - Code completion for members of a field of a deferred class

instance

Change-Id: Idfd8535e62fa35bbed3385c5489fae81e65b64d5
Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
Nathan Ridge 2015-03-02 02:13:36 -05:00 committed by Sergey Prigogin
parent da922a8b01
commit d31d768681
4 changed files with 74 additions and 11 deletions

View file

@ -30,6 +30,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
/**
* Models the scope represented by an unknown type (e.g.: typeof(template type parameter)).
@ -147,14 +148,14 @@ public class CPPUnknownTypeScope implements ICPPInternalUnknownScope {
@Override
public final IBinding[] getBindings(ScopeLookupData lookup) {
if (lookup.isPrefixLookup()) {
if (fScopeType instanceof ICPPDeferredClassInstance) {
ICPPDeferredClassInstance instance = (ICPPDeferredClassInstance) fScopeType;
IScope scope = instance.getClassTemplate().getCompositeScope();
if (scope != null) {
return scope.getBindings(lookup);
}
}
return IBinding.EMPTY_BINDING_ARRAY;
// If name lookup is performed for the purpose of code completion in a dependent context,
// try to give some useful results heuristically.
IScope scope = CPPSemantics.heuristicallyFindConcreteScopeForType(fScopeType,
lookup.getLookupPoint());
if (scope != null) {
return scope.getBindings(lookup);
}
return IBinding.EMPTY_BINDING_ARRAY;
}
IASTName lookupName= lookup.getLookupName();
if (lookupName != null)

View file

@ -22,7 +22,6 @@ import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplateInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
@ -278,9 +277,9 @@ public class AccessContext {
if (scopeType instanceof ICPPDeferredClassInstance) {
return ((ICPPDeferredClassInstance) scopeType).getClassTemplate();
}
} else {
scope = CPPSemantics.getParentScope(scope, data.getTranslationUnit());
}
scope = CPPSemantics.getParentScope(scope, data.getTranslationUnit());
}
if (scope instanceof ICPPClassScope) {
return ((ICPPClassScope) scope).getClassType();

View file

@ -83,6 +83,7 @@ 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.IField;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
@ -3951,4 +3952,48 @@ public class CPPSemantics {
return binding;
}
/**
* Given a dependent type, heuristically try to find a concrete scope (i.e. not an unknown scope) for it.
* @param point the point of instantiation for name lookups
*/
public static IScope heuristicallyFindConcreteScopeForType(IType type, IASTNode point) {
if (type instanceof ICPPDeferredClassInstance) {
// If this scope is for a deferred-class-instance, use the scope of the primary template.
ICPPDeferredClassInstance instance = (ICPPDeferredClassInstance) type;
return instance.getClassTemplate().getCompositeScope();
} else if (type instanceof TypeOfDependentExpression) {
// If this scope is for the id-expression of a field reference, and the field owner
// is a deferred-class-instance, look up the field in the scope of the primary template,
// and use the scope of the resulting field type.
ICPPEvaluation evaluation = ((TypeOfDependentExpression) type).getEvaluation();
if (evaluation instanceof EvalID) {
EvalID evalId = (EvalID) evaluation;
ICPPEvaluation fieldOwner = evalId.getFieldOwner();
if (fieldOwner != null) {
IType fieldOwnerType = fieldOwner.getTypeOrFunctionSet(point);
if (fieldOwnerType instanceof ICPPDeferredClassInstance) {
ICPPDeferredClassInstance instance = (ICPPDeferredClassInstance) fieldOwnerType;
IScope scope = instance.getClassTemplate().getCompositeScope();
LookupData lookup = new LookupData(evalId.getName(), evalId.getTemplateArgs(), point);
lookup.qualified = evalId.isQualified();
try {
CPPSemantics.lookup(lookup, scope);
} catch (DOMException e) {
return null;
}
IBinding[] bindings = lookup.getFoundBindings();
if (bindings.length == 1 && bindings[0] instanceof IField) {
IType fieldType = ((IField) bindings[0]).getType();
if (fieldType instanceof ICompositeType) {
return ((ICompositeType) fieldType).getCompositeScope();
}
}
}
}
}
}
// TODO(nathanridge): Handle more cases.
return null;
}
}

View file

@ -1668,4 +1668,22 @@ public class CompletionTests extends AbstractContentAssistTest {
final String[] expectedDisplay = { "other_tpl<typename T1, typename T2 = tpl<T1>>" };
assertContentAssistResults(fCursorOffset, expectedDisplay, true, DISPLAY);
}
// struct A {
// void foo();
// };
//
// template <typename>
// struct B {
// A val;
// };
//
// template <typename T>
// void test(B<T> b) {
// b.val./*cursor*/
// }
public void testFieldOfDeferredClassInstance_Bug402617() throws Exception {
final String[] expected = { "A", "foo(void)" };
assertContentAssistResults(fCursorOffset, expected, true, ID);
}
}