mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-09-04 14:13:24 +02:00
Bug 472818 - Numerous improvements to HeuristicResolver
Notable improvements include: - better handling of typedefs and reference types - support for specialization of dependent lookup results - support for nested templates Change-Id: Id7b20e40bf31507b4e1743a7ae5898b1a85ade17
This commit is contained in:
parent
6df72650e4
commit
453e429d5c
3 changed files with 340 additions and 42 deletions
|
@ -273,8 +273,59 @@ public class CPPTemplates {
|
||||||
return e.getProblem();
|
return e.getProblem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates an alias template with the given arguments.
|
||||||
|
*/
|
||||||
|
public static IBinding instantiateAliasTemplate(ICPPAliasTemplate aliasTemplate,
|
||||||
|
ICPPTemplateArgument[] args, IASTNode point) {
|
||||||
|
try {
|
||||||
|
args = addDefaultArguments(aliasTemplate, args, point);
|
||||||
|
if (args == null) {
|
||||||
|
return createProblem(aliasTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
|
||||||
|
}
|
||||||
|
ICPPTemplateParameterMap parameterMap = createParameterMap(aliasTemplate, args, point);
|
||||||
|
if (parameterMap == null) {
|
||||||
|
return createProblem(aliasTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
|
||||||
|
}
|
||||||
|
IType aliasedType = aliasTemplate.getType();
|
||||||
|
IBinding owner = aliasTemplate.getOwner();
|
||||||
|
return createAliasTemplaceInstance(aliasTemplate, args, parameterMap, aliasedType, owner, point);
|
||||||
|
} catch (DOMException e) {
|
||||||
|
return e.getProblem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a specialization of an alias template with the given arguments.
|
||||||
|
*
|
||||||
|
* TODO(nathanridge): The reason we have this method is that we (incorrectly) represent
|
||||||
|
* specializations of alias templates as alias template instances. A specialization of
|
||||||
|
* an alias template is an alias template, so it needs to be instantiated to produce
|
||||||
|
* an actual alias template instance. Actual alias template instances do not need to be
|
||||||
|
* instantiated.
|
||||||
|
*/
|
||||||
|
public static IBinding instantiateAliasTemplateInstance(ICPPAliasTemplateInstance aliasTemplateInstance,
|
||||||
|
ICPPTemplateArgument[] args, IASTNode point) {
|
||||||
|
ICPPAliasTemplate aliasTemplate = aliasTemplateInstance.getTemplateDefinition();
|
||||||
|
try {
|
||||||
|
args = addDefaultArguments(aliasTemplate, args, point);
|
||||||
|
if (args == null) {
|
||||||
|
return createProblem(aliasTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
|
||||||
|
}
|
||||||
|
ICPPTemplateParameterMap parameterMap = createParameterMap(aliasTemplate, args, point);
|
||||||
|
if (parameterMap == null) {
|
||||||
|
return createProblem(aliasTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
|
||||||
|
}
|
||||||
|
IType aliasedType = aliasTemplateInstance.getType();
|
||||||
|
IBinding owner = aliasTemplateInstance.getOwner();
|
||||||
|
return createAliasTemplaceInstance(aliasTemplate, args, parameterMap, aliasedType, owner, point);
|
||||||
|
} catch (DOMException e) {
|
||||||
|
return e.getProblem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IBinding createProblem(ICPPPartiallySpecializable template, int id, IASTNode point) {
|
private static IBinding createProblem(ICPPTemplateDefinition template, int id, IASTNode point) {
|
||||||
return new ProblemBinding(point, id, template.getNameCharArray());
|
return new ProblemBinding(point, id, template.getNameCharArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,35 +768,17 @@ public class CPPTemplates {
|
||||||
if (template instanceof ICPPAliasTemplate) {
|
if (template instanceof ICPPAliasTemplate) {
|
||||||
ICPPAliasTemplate aliasTemplate = (ICPPAliasTemplate) template;
|
ICPPAliasTemplate aliasTemplate = (ICPPAliasTemplate) template;
|
||||||
ICPPTemplateArgument[] args = createTemplateArgumentArray(id);
|
ICPPTemplateArgument[] args = createTemplateArgumentArray(id);
|
||||||
args = addDefaultArguments(aliasTemplate, args, id);
|
return instantiateAliasTemplate(aliasTemplate, args, id);
|
||||||
if (args == null) {
|
|
||||||
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, templateName.toCharArray());
|
|
||||||
}
|
|
||||||
CPPTemplateParameterMap parameterMap = createParameterMap(aliasTemplate, args, id);
|
|
||||||
if (parameterMap == null) {
|
|
||||||
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, templateName.toCharArray());
|
|
||||||
}
|
|
||||||
IType aliasedType = aliasTemplate.getType();
|
|
||||||
IBinding owner = template.getOwner();
|
|
||||||
return createAliasTemplaceInstance(aliasTemplate, args, parameterMap, aliasedType, owner, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alias template instance.
|
// Alias template instance.
|
||||||
if (template instanceof ICPPAliasTemplateInstance) {
|
if (template instanceof ICPPAliasTemplateInstance) {
|
||||||
|
// TODO(nathanridge): Remove this branch once we properly represent
|
||||||
|
// specializations of alias templates (which will then implement
|
||||||
|
// ICPPAliasTemplate and be caught by the previous branch).
|
||||||
ICPPAliasTemplateInstance aliasTemplateInstance = (ICPPAliasTemplateInstance) template;
|
ICPPAliasTemplateInstance aliasTemplateInstance = (ICPPAliasTemplateInstance) template;
|
||||||
ICPPTemplateArgument[] args = createTemplateArgumentArray(id);
|
ICPPTemplateArgument[] args = createTemplateArgumentArray(id);
|
||||||
ICPPAliasTemplate aliasTemplate = aliasTemplateInstance.getTemplateDefinition();
|
return instantiateAliasTemplateInstance(aliasTemplateInstance, args, id);
|
||||||
args = addDefaultArguments(aliasTemplate, args, id);
|
|
||||||
if (args == null) {
|
|
||||||
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, templateName.toCharArray());
|
|
||||||
}
|
|
||||||
CPPTemplateParameterMap parameterMap = createParameterMap(aliasTemplate, args, id);
|
|
||||||
if (parameterMap == null) {
|
|
||||||
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, templateName.toCharArray());
|
|
||||||
}
|
|
||||||
IType aliasedType = aliasTemplateInstance.getType();
|
|
||||||
IBinding owner = aliasTemplateInstance.getOwner();
|
|
||||||
return createAliasTemplaceInstance(aliasTemplate, args, parameterMap, aliasedType, owner, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class or variable template.
|
// Class or variable template.
|
||||||
|
@ -817,9 +850,9 @@ public class CPPTemplates {
|
||||||
return e.getProblem();
|
return e.getProblem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IBinding createAliasTemplaceInstance(ICPPAliasTemplate aliasTemplate,
|
private static IBinding createAliasTemplaceInstance(ICPPAliasTemplate aliasTemplate,
|
||||||
ICPPTemplateArgument[] args, CPPTemplateParameterMap parameterMap, IType aliasedType,
|
ICPPTemplateArgument[] args, ICPPTemplateParameterMap parameterMap, IType aliasedType,
|
||||||
IBinding owner, IASTNode point) {
|
IBinding owner, IASTNode point) {
|
||||||
InstantiationContext context = createInstantiationContext(parameterMap, owner, point);
|
InstantiationContext context = createInstantiationContext(parameterMap, owner, point);
|
||||||
IType instantiatedType = instantiateType(aliasedType, context);
|
IType instantiatedType = instantiateType(aliasedType, context);
|
||||||
|
|
|
@ -16,19 +16,30 @@ import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
||||||
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.IFunction;
|
import org.eclipse.cdt.core.dom.ast.IFunction;
|
||||||
import org.eclipse.cdt.core.dom.ast.IPointerType;
|
import org.eclipse.cdt.core.dom.ast.IPointerType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
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.IVariable;
|
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
|
||||||
|
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.ICPPClassSpecialization;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
|
||||||
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.ICPPEnumeration;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredClassInstance;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownMember;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownMember;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownMemberClass;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownMemberClass;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownMemberClassInstance;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
|
||||||
|
|
||||||
public class HeuristicResolver {
|
public class HeuristicResolver {
|
||||||
|
@ -40,7 +51,7 @@ public class HeuristicResolver {
|
||||||
*/
|
*/
|
||||||
public static IScope findConcreteScopeForType(IType type, IASTNode point) {
|
public static IScope findConcreteScopeForType(IType type, IASTNode point) {
|
||||||
if (type instanceof ICPPUnknownType) {
|
if (type instanceof ICPPUnknownType) {
|
||||||
type = resolveUnknownType((ICPPUnknownType) type, point);
|
type = resolveUnknownType((ICPPUnknownType) type, point, SemanticUtil.TDEF | SemanticUtil.REF);
|
||||||
}
|
}
|
||||||
if (type instanceof ICompositeType) {
|
if (type instanceof ICompositeType) {
|
||||||
return ((ICompositeType) type).getCompositeScope();
|
return ((ICompositeType) type).getCompositeScope();
|
||||||
|
@ -48,10 +59,103 @@ public class HeuristicResolver {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for lookInside().
|
||||||
|
* Specializes the given bindings in the given context.
|
||||||
|
*
|
||||||
|
* @param point the point of instantiation for name lookups
|
||||||
|
*/
|
||||||
|
private static IBinding[] specializeBindings(IBinding[] bindings, ICPPClassSpecialization context,
|
||||||
|
IASTNode point) {
|
||||||
|
IBinding[] result = new IBinding[bindings.length];
|
||||||
|
for (int i = 0; i < bindings.length; ++i) {
|
||||||
|
result[i] = context.specializeMember(bindings[i], point);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extension of CPPDeferredClassInstance that implements ICPPClassSpecialization,
|
||||||
|
* allowing its members to be specialized via specializeMember().
|
||||||
|
*/
|
||||||
|
private static class CPPDependentClassInstance extends CPPDeferredClassInstance
|
||||||
|
implements ICPPClassSpecialization {
|
||||||
|
|
||||||
|
public CPPDependentClassInstance(ICPPDeferredClassInstance deferredInstance) {
|
||||||
|
super(deferredInstance.getClassTemplate(), deferredInstance.getTemplateArguments());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPClassType getSpecializedBinding() {
|
||||||
|
return (ICPPClassType) super.getSpecializedBinding();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This overload of specializeMember() is all we're interested in.
|
||||||
|
// Everything else is unsupported.
|
||||||
|
@Override
|
||||||
|
public IBinding specializeMember(IBinding binding, IASTNode point) {
|
||||||
|
return CPPTemplates.createSpecialization(this, binding, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinding specializeMember(IBinding binding) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPBase[] getBases(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPConstructor[] getConstructors(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPField[] getDeclaredFields(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPMethod[] getMethods(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPMethod[] getAllDeclaredMethods(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPMethod[] getDeclaredMethods(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinding[] getFriends(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IField[] getFields(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICPPClassType[] getNestedClasses(IASTNode point) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for resolveUnknownType() and resolveUnknownBinding().
|
* Helper function for resolveUnknownType() and resolveUnknownBinding().
|
||||||
* Heuristically resolves the given unknown type and performs name lookup inside it.
|
* Heuristically resolves the given unknown type and performs name lookup inside it.
|
||||||
*
|
*
|
||||||
|
* If name lookup is performed inside a template scope to approximate lookup
|
||||||
|
* in the scope of a dependent instantiation, the lookup results are
|
||||||
|
* specialized in the context of the dependent instantiation.
|
||||||
|
*
|
||||||
* @param ownerType the type to perform name lookup inside
|
* @param ownerType the type to perform name lookup inside
|
||||||
* @param isPointerDeref true if 'ownerType' is a pointer type
|
* @param isPointerDeref true if 'ownerType' is a pointer type
|
||||||
* @param name the name to be looked up
|
* @param name the name to be looked up
|
||||||
|
@ -61,23 +165,50 @@ public class HeuristicResolver {
|
||||||
*/
|
*/
|
||||||
private static IBinding[] lookInside(IType ownerType, boolean isPointerDeref, char[] name,
|
private static IBinding[] lookInside(IType ownerType, boolean isPointerDeref, char[] name,
|
||||||
ICPPTemplateArgument[] templateArgs, IASTNode point) {
|
ICPPTemplateArgument[] templateArgs, IASTNode point) {
|
||||||
// The pointer type might be outside of the dependent type...
|
// If this is a pointer dereference, the pointer type might be outside of the dependent type.
|
||||||
ownerType = SemanticUtil.getSimplifiedType(ownerType);
|
ownerType = SemanticUtil.getSimplifiedType(ownerType);
|
||||||
if (isPointerDeref && ownerType instanceof IPointerType) {
|
if (isPointerDeref && ownerType instanceof IPointerType) {
|
||||||
ownerType = ((IPointerType) ownerType).getType();
|
ownerType = ((IPointerType) ownerType).getType();
|
||||||
isPointerDeref = false;
|
isPointerDeref = false;
|
||||||
}
|
}
|
||||||
if (ownerType instanceof ICPPUnknownType) {
|
if (ownerType instanceof ICPPUnknownType) {
|
||||||
IType lookupType = resolveUnknownType((ICPPUnknownType) ownerType, point);
|
// Here we have a loop similar to the one in resolveUnknownType(), but we stop when
|
||||||
// ... or inside the dependent type.
|
// 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;
|
||||||
|
lookupType = specializationContext.getSpecializedBinding();
|
||||||
|
break;
|
||||||
|
} else if (ownerType instanceof ICPPDeferredClassInstance) {
|
||||||
|
specializationContext = new CPPDependentClassInstance(
|
||||||
|
(ICPPDeferredClassInstance) ownerType);
|
||||||
|
lookupType = specializationContext.getSpecializedBinding();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
IType resolvedType = resolveUnknownTypeOnce((ICPPUnknownType) ownerType, point);
|
||||||
|
resolvedType = SemanticUtil.getNestedType(resolvedType, SemanticUtil.TDEF | SemanticUtil.REF);
|
||||||
|
if (resolvedType == ownerType || !(resolvedType instanceof ICPPUnknownType)) {
|
||||||
|
lookupType = resolvedType;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
ownerType = resolvedType;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a pointer dereference, and the pointer type wasn't outside the
|
||||||
|
// dependent type, it might be inside the dependent type.
|
||||||
if (isPointerDeref) {
|
if (isPointerDeref) {
|
||||||
lookupType = SemanticUtil.getSimplifiedType(lookupType);
|
|
||||||
if (lookupType instanceof IPointerType) {
|
if (lookupType instanceof IPointerType) {
|
||||||
lookupType = ((IPointerType) lookupType).getType();
|
lookupType = ((IPointerType) lookupType).getType();
|
||||||
} else {
|
} else {
|
||||||
lookupType = null;
|
lookupType = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IScope lookupScope = null;
|
IScope lookupScope = null;
|
||||||
if (lookupType instanceof ICPPClassType) {
|
if (lookupType instanceof ICPPClassType) {
|
||||||
lookupScope = ((ICPPClassType) lookupType).getCompositeScope();
|
lookupScope = ((ICPPClassType) lookupType).getCompositeScope();
|
||||||
|
@ -91,6 +222,9 @@ public class HeuristicResolver {
|
||||||
CPPSemantics.lookup(lookup, lookupScope);
|
CPPSemantics.lookup(lookup, lookupScope);
|
||||||
IBinding[] foundBindings = lookup.getFoundBindings();
|
IBinding[] foundBindings = lookup.getFoundBindings();
|
||||||
if (foundBindings.length > 0) {
|
if (foundBindings.length > 0) {
|
||||||
|
if (specializationContext != null) {
|
||||||
|
foundBindings = specializeBindings(foundBindings, specializationContext, point);
|
||||||
|
}
|
||||||
return foundBindings;
|
return foundBindings;
|
||||||
}
|
}
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
|
@ -102,7 +236,7 @@ public class HeuristicResolver {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for resolveUnknownType().
|
* Helper function for resolveUnknownType().
|
||||||
* Returns the type of a binding, or if the binding is a type, that type.
|
* Returns the type of a binding.
|
||||||
*/
|
*/
|
||||||
private static IType typeForBinding(IBinding binding) {
|
private static IType typeForBinding(IBinding binding) {
|
||||||
if (binding instanceof IType) {
|
if (binding instanceof IType) {
|
||||||
|
@ -118,16 +252,47 @@ public class HeuristicResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an unknown type, heuristically tries to find a concrete type (i.e. not an unknown type)
|
* Given an unknown type, heuristically tries to find a concrete type
|
||||||
* corresponding to it.
|
* (i.e. not an unknown type) corresponding to it.
|
||||||
*
|
*
|
||||||
* Returns null if no heuristic resolution could be performed.
|
* Returns null if no heuristic resolution could be performed.
|
||||||
|
*
|
||||||
|
* Multiple rounds of resolution are performed, as the result of a single
|
||||||
|
* round may yield a type which is still dependent. Resolution stops when
|
||||||
|
* a concrete type is found, or the resolution of the last resolution
|
||||||
|
* round is the same as the result of the previous resolution round.
|
||||||
|
* In between each round, typedefs are unwrapped.
|
||||||
|
*
|
||||||
* @param point the point of instantiation for lookups
|
* @param point the point of instantiation for lookups
|
||||||
*/
|
*/
|
||||||
private static IType resolveUnknownType(ICPPUnknownType type, IASTNode point) {
|
private static IType resolveUnknownType(ICPPUnknownType type, IASTNode point) {
|
||||||
|
return resolveUnknownType(type, point, SemanticUtil.TDEF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to resolveUnknownType(type, point), but allows specifying
|
||||||
|
* things other than typedefs to unwrap between rounds of resolution
|
||||||
|
* (e.g. references).
|
||||||
|
*/
|
||||||
|
private static IType resolveUnknownType(ICPPUnknownType type, IASTNode point, int unwrapOptions) {
|
||||||
|
while (true) {
|
||||||
|
IType resolvedType = resolveUnknownTypeOnce(type, point);
|
||||||
|
resolvedType = SemanticUtil.getNestedType(resolvedType, unwrapOptions);
|
||||||
|
if (resolvedType != type && resolvedType instanceof ICPPUnknownType) {
|
||||||
|
type = (ICPPUnknownType) resolvedType;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return resolvedType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for resolveUnknownType() which does one round of resolution.
|
||||||
|
*/
|
||||||
|
private static IType resolveUnknownTypeOnce(ICPPUnknownType type, IASTNode point) {
|
||||||
if (type instanceof ICPPDeferredClassInstance) {
|
if (type instanceof ICPPDeferredClassInstance) {
|
||||||
return ((ICPPDeferredClassInstance) type).getClassTemplate();
|
ICPPDeferredClassInstance deferredInstance = (ICPPDeferredClassInstance) type;
|
||||||
|
return deferredInstance.getClassTemplate();
|
||||||
} else if (type instanceof TypeOfDependentExpression) {
|
} else if (type instanceof TypeOfDependentExpression) {
|
||||||
ICPPEvaluation evaluation = ((TypeOfDependentExpression) type).getEvaluation();
|
ICPPEvaluation evaluation = ((TypeOfDependentExpression) type).getEvaluation();
|
||||||
if (evaluation instanceof EvalUnary) {
|
if (evaluation instanceof EvalUnary) {
|
||||||
|
@ -138,7 +303,6 @@ public class HeuristicResolver {
|
||||||
IType argument = unary.getArgument().getType(point);
|
IType argument = unary.getArgument().getType(point);
|
||||||
if (argument instanceof ICPPUnknownType) {
|
if (argument instanceof ICPPUnknownType) {
|
||||||
IType resolved = resolveUnknownType((ICPPUnknownType) argument, point);
|
IType resolved = resolveUnknownType((ICPPUnknownType) argument, point);
|
||||||
resolved = SemanticUtil.getSimplifiedType(resolved);
|
|
||||||
if (resolved instanceof IPointerType) {
|
if (resolved instanceof IPointerType) {
|
||||||
return ((IPointerType) resolved).getType();
|
return ((IPointerType) resolved).getType();
|
||||||
}
|
}
|
||||||
|
@ -148,8 +312,9 @@ public class HeuristicResolver {
|
||||||
EvalID id = (EvalID) evaluation;
|
EvalID id = (EvalID) evaluation;
|
||||||
ICPPEvaluation fieldOwner = id.getFieldOwner();
|
ICPPEvaluation fieldOwner = id.getFieldOwner();
|
||||||
if (fieldOwner != null) {
|
if (fieldOwner != null) {
|
||||||
IBinding[] candidates = lookInside(fieldOwner.getType(point),
|
IType fieldOwnerType = fieldOwner.getType(point);
|
||||||
id.isPointerDeref(), id.getName(), id.getTemplateArgs(), point);
|
IBinding[] candidates = lookInside(fieldOwnerType, id.isPointerDeref(), id.getName(),
|
||||||
|
id.getTemplateArgs(), point);
|
||||||
if (candidates.length == 1) {
|
if (candidates.length == 1) {
|
||||||
return typeForBinding(candidates[0]);
|
return typeForBinding(candidates[0]);
|
||||||
}
|
}
|
||||||
|
@ -166,11 +331,27 @@ public class HeuristicResolver {
|
||||||
// TODO(nathanridge): Handle more cases.
|
// TODO(nathanridge): Handle more cases.
|
||||||
} else if (type instanceof ICPPUnknownMemberClass) {
|
} else if (type instanceof ICPPUnknownMemberClass) {
|
||||||
ICPPUnknownMemberClass member = (ICPPUnknownMemberClass) type;
|
ICPPUnknownMemberClass member = (ICPPUnknownMemberClass) type;
|
||||||
IBinding[] candidates = lookInside(member.getOwnerType(), false, member.getNameCharArray(),
|
IType ownerType = member.getOwnerType();
|
||||||
null, point);
|
IBinding[] candidates = lookInside(ownerType, false, member.getNameCharArray(), null, point);
|
||||||
if (candidates.length == 1) {
|
if (candidates.length == 1) {
|
||||||
if (candidates[0] instanceof IType) {
|
if (candidates[0] instanceof IType) {
|
||||||
return (IType) candidates[0];
|
IType result = (IType) candidates[0];
|
||||||
|
if (type instanceof ICPPUnknownMemberClassInstance) {
|
||||||
|
ICPPTemplateArgument[] args = ((ICPPUnknownMemberClassInstance) type).getArguments();
|
||||||
|
if (result instanceof ICPPClassTemplate) {
|
||||||
|
result = (IType) CPPTemplates.instantiate((ICPPClassTemplate) result, args, point);
|
||||||
|
} else if (result instanceof ICPPAliasTemplate) {
|
||||||
|
result = (IType) CPPTemplates.instantiateAliasTemplate((ICPPAliasTemplate) result,
|
||||||
|
args, point);
|
||||||
|
} else if (result instanceof ICPPAliasTemplateInstance) {
|
||||||
|
// TODO(nathanridge): Remove this branch once we properly represent
|
||||||
|
// specializations of alias templates (which will then implement
|
||||||
|
// ICPPAliasTemplate and be caught by the previous branch).
|
||||||
|
result = (IType) CPPTemplates.instantiateAliasTemplateInstance(
|
||||||
|
(ICPPAliasTemplateInstance) result, args, point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1736,4 +1736,88 @@ public class CompletionTests extends AbstractContentAssistTest {
|
||||||
final String[] expected = {};
|
final String[] expected = {};
|
||||||
assertCompletionResults(fCursorOffset, expected, ID);
|
assertCompletionResults(fCursorOffset, expected, ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// template <typename T>
|
||||||
|
// struct vector {
|
||||||
|
// T& front();
|
||||||
|
// };
|
||||||
|
// template <class T>
|
||||||
|
// void foo(vector<vector<T>> a) {
|
||||||
|
// a.front()./*cursor*/
|
||||||
|
// }
|
||||||
|
public void testDependentScopes_bug472818a() throws Exception {
|
||||||
|
final String[] expected = { "vector<typename T>", "front(void)" };
|
||||||
|
assertCompletionResults(fCursorOffset, expected, ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// template <typename T>
|
||||||
|
// struct vector {
|
||||||
|
// T& front();
|
||||||
|
// };
|
||||||
|
// template <class T>
|
||||||
|
// void foo(vector<vector<vector<T>>> a) {
|
||||||
|
// a.front().front()./*cursor*/
|
||||||
|
// }
|
||||||
|
public void testDependentScopes_bug472818b() throws Exception {
|
||||||
|
final String[] expected = { "vector<typename T>", "front(void)" };
|
||||||
|
assertCompletionResults(fCursorOffset, expected, ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // This is a simplification of the actual std::vector implementation
|
||||||
|
// // that ships with gcc 5.1's libstdc++.
|
||||||
|
// template <typename T>
|
||||||
|
// struct allocator {
|
||||||
|
// typedef T value_type;
|
||||||
|
// template <typename U>
|
||||||
|
// struct rebind {
|
||||||
|
// typedef allocator<U> other;
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
// template <typename Alloc, typename T>
|
||||||
|
// struct alloctr_rebind {
|
||||||
|
// typedef typename Alloc::template rebind<T>::other type;
|
||||||
|
// };
|
||||||
|
// template <typename Alloc>
|
||||||
|
// struct allocator_traits {
|
||||||
|
// typedef typename Alloc::value_type value_type;
|
||||||
|
// template <typename T>
|
||||||
|
// using rebind_alloc = typename alloctr_rebind<Alloc, T>::type;
|
||||||
|
// };
|
||||||
|
// template <typename Alloc>
|
||||||
|
// struct alloc_traits {
|
||||||
|
// typedef allocator_traits<Alloc> base_type;
|
||||||
|
// typedef typename base_type::value_type value_type;
|
||||||
|
// typedef value_type& reference;
|
||||||
|
// template <typename T>
|
||||||
|
// struct rebind {
|
||||||
|
// typedef typename base_type::template rebind_alloc<T> other;
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
// template <typename T, typename Alloc>
|
||||||
|
// struct vector_base {
|
||||||
|
// typedef typename alloc_traits<Alloc>::template rebind<T>::other allocator_type;
|
||||||
|
// };
|
||||||
|
// template <typename T, typename Alloc = allocator<T>>
|
||||||
|
// struct vector {
|
||||||
|
// typedef vector_base<T, Alloc> base_type;
|
||||||
|
// typedef typename base_type::allocator_type allocator_type;
|
||||||
|
// typedef alloc_traits<allocator_type> alloc_traits_type;
|
||||||
|
// typedef typename alloc_traits_type::reference reference;
|
||||||
|
// reference front();
|
||||||
|
// };
|
||||||
|
// template <class T>
|
||||||
|
// void foo(vector<vector<vector<T>>> a) {
|
||||||
|
// a.front().front()./*cursor*/
|
||||||
|
// }
|
||||||
|
public void testDependentScopes_bug472818c() throws Exception {
|
||||||
|
final String[] expected = {
|
||||||
|
"vector<typename T, typename Alloc = allocator<T>>",
|
||||||
|
"base_type",
|
||||||
|
"allocator_type",
|
||||||
|
"alloc_traits_type",
|
||||||
|
"reference",
|
||||||
|
"front(void)"
|
||||||
|
};
|
||||||
|
assertCompletionResults(fCursorOffset, expected, ID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue