diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java index f404bcced00..ae42c4ae098 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java @@ -53,6 +53,7 @@ public class HeuristicResolver { if (type instanceof ICPPUnknownType) { type = resolveUnknownType((ICPPUnknownType) type, point, SemanticUtil.TDEF | SemanticUtil.REF); } + type = SemanticUtil.getNestedType(type, SemanticUtil.PTR); if (type instanceof ICompositeType) { return ((ICompositeType) type).getCompositeScope(); } @@ -171,30 +172,31 @@ public class HeuristicResolver { ownerType = ((IPointerType) ownerType).getType(); isPointerDeref = false; } - if (ownerType instanceof ICPPUnknownType) { + + IType lookupType = ownerType; + ICPPClassSpecialization specializationContext = null; + if (lookupType instanceof ICPPUnknownType) { // Here we have a loop similar to the one in resolveUnknownType(), but we stop when // we get a result that's an ICPPClassSpecialization or an ICPPDeferredClassInstance, // so we can use it to specialize the lookup results as appropriate. - IType lookupType; - ICPPClassSpecialization specializationContext = null; while (true) { - if (ownerType instanceof ICPPClassSpecialization) { - specializationContext = (ICPPClassSpecialization) ownerType; + if (lookupType instanceof ICPPClassSpecialization) { + specializationContext = (ICPPClassSpecialization) lookupType; lookupType = specializationContext.getSpecializedBinding(); break; - } else if (ownerType instanceof ICPPDeferredClassInstance) { + } else if (lookupType instanceof ICPPDeferredClassInstance) { specializationContext = new CPPDependentClassInstance( - (ICPPDeferredClassInstance) ownerType); + (ICPPDeferredClassInstance) lookupType); lookupType = specializationContext.getSpecializedBinding(); break; } - IType resolvedType = resolveUnknownTypeOnce((ICPPUnknownType) ownerType, point); + IType resolvedType = resolveUnknownTypeOnce((ICPPUnknownType) lookupType, point); resolvedType = SemanticUtil.getNestedType(resolvedType, SemanticUtil.TDEF | SemanticUtil.REF); - if (resolvedType == ownerType || !(resolvedType instanceof ICPPUnknownType)) { + if (resolvedType == lookupType || !(resolvedType instanceof ICPPUnknownType)) { lookupType = resolvedType; break; } else { - ownerType = resolvedType; + lookupType = resolvedType; continue; } } @@ -208,27 +210,27 @@ public class HeuristicResolver { lookupType = null; } } + } - IScope lookupScope = null; - if (lookupType instanceof ICPPClassType) { - lookupScope = ((ICPPClassType) lookupType).getCompositeScope(); - } else if (lookupType instanceof ICPPEnumeration) { - lookupScope = ((ICPPEnumeration) lookupType).asScope(); - } - if (lookupScope != null) { - LookupData lookup = new LookupData(name, templateArgs, point); - lookup.fHeuristicBaseLookup = true; - try { - CPPSemantics.lookup(lookup, lookupScope); - IBinding[] foundBindings = lookup.getFoundBindings(); - if (foundBindings.length > 0) { - if (specializationContext != null) { - foundBindings = specializeBindings(foundBindings, specializationContext, point); - } - return foundBindings; + IScope lookupScope = null; + if (lookupType instanceof ICPPClassType) { + lookupScope = ((ICPPClassType) lookupType).getCompositeScope(); + } else if (lookupType instanceof ICPPEnumeration) { + lookupScope = ((ICPPEnumeration) lookupType).asScope(); + } + if (lookupScope != null) { + LookupData lookup = new LookupData(name, templateArgs, point); + lookup.fHeuristicBaseLookup = true; + try { + CPPSemantics.lookup(lookup, lookupScope); + IBinding[] foundBindings = lookup.getFoundBindings(); + if (foundBindings.length > 0) { + if (specializationContext != null) { + foundBindings = specializeBindings(foundBindings, specializationContext, point); } - } catch (DOMException e) { + return foundBindings; } + } catch (DOMException e) { } } return IBinding.EMPTY_BINDING_ARRAY; @@ -265,7 +267,7 @@ public class HeuristicResolver { * * @param point the point of instantiation for lookups */ - private static IType resolveUnknownType(ICPPUnknownType type, IASTNode point) { + public static IType resolveUnknownType(ICPPUnknownType type, IASTNode point) { return resolveUnknownType(type, point, SemanticUtil.TDEF); } @@ -327,6 +329,11 @@ public class HeuristicResolver { functionType = resolveUnknownType((ICPPUnknownType) functionType, point); } return ExpressionTypes.typeFromFunctionCall(functionType); + } else if (evaluation instanceof EvalMemberAccess) { + IBinding member = ((EvalMemberAccess) evaluation).getMember(); + // Presumably the type will be unknown. That's fine, it will be + // resolved during subsequent resolution rounds. + return typeForBinding(member); } // TODO(nathanridge): Handle more cases. } else if (type instanceof ICPPUnknownMemberClass) { diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java index 4ae506111b4..1c966cf24db 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java @@ -1820,4 +1820,21 @@ public class CompletionTests extends AbstractContentAssistTest { }; assertCompletionResults(fCursorOffset, expected, ID); } + + // template + // struct D { + // struct C { + // C* c; + // }; + // C c; + // void f() { + // c.c->c->c./*cursor*/ + // } + // }; + public void testDependentMemberChain_bug478121() throws Exception { + setReplaceDotWithArrow(true); + final String[] expected = { "C", "c" }; + assertCompletionResults(fCursorOffset, expected, ID); + assertDotReplacedWithArrow(); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CContentAssistProcessor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CContentAssistProcessor.java index 24e60fe2238..662662f050e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CContentAssistProcessor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CContentAssistProcessor.java @@ -44,6 +44,8 @@ import org.eclipse.cdt.ui.text.ICCompletionProposal; import org.eclipse.cdt.ui.text.contentassist.ContentAssistInvocationContext; import org.eclipse.cdt.ui.text.contentassist.IProposalFilter; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.HeuristicResolver; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.ui.preferences.ProposalFilterPreferencesUtil; @@ -273,6 +275,10 @@ public class CContentAssistProcessor extends ContentAssistProcessor { IASTFieldReference ref = (IASTFieldReference) names[0].getParent(); IASTExpression ownerExpr = ref.getFieldOwner(); IType ownerExprType = SemanticUtil.getNestedType(ownerExpr.getExpressionType(), SemanticUtil.TDEF); + if (ownerExprType instanceof ICPPUnknownType) { + ownerExprType = HeuristicResolver.resolveUnknownType((ICPPUnknownType) ownerExprType, + names[0]); + } if (ownerExprType instanceof IPointerType) { context = replaceDotWithArrow(viewer, offset, isCompletion, context, activationChar); }