1
0
Fork 0
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:
Nathan Ridge 2016-01-31 23:25:15 -05:00
parent 6df72650e4
commit 453e429d5c
3 changed files with 340 additions and 42 deletions

View file

@ -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);

View file

@ -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;
} }
} }
} }

View file

@ -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);
}
} }