blob: dd69a67f381b33d177c8db49e2b7032cb8604be7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2016 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
* Thomas Corbat (IFS)
* Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext.getContextClassSpecialization;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
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;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter;
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.ICPPClassScope;
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.ICPPClassTemplatePartialSpecialization;
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.ICPPConstructorSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumerationSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFieldTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
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.ICPPParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPPartialSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPPartiallySpecializable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTypeSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUnaryTypeTransformation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArraySet;
import org.eclipse.cdt.core.parser.util.ObjectMap;
import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.DependentValue;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.ProblemFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPAliasTemplateInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization.RecursionResolvingBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplatePartialSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplatePartialSpecializationSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumerationSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldTemplatePartialSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterSpecialization;
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.CPPTemplateDefinition;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeParameterSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTemplateParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTemplateParameterSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeParameterSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTypedefSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMemberClass;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownMethod;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUsingDeclarationSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplate;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplatePartialSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPASTInternalTemplateDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPComputableFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInstanceCache;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalClassTemplate;
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.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.InstantiationContext;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
import org.eclipse.cdt.internal.core.index.IIndexType;
/**
* Collection of static methods to perform template instantiation, member specialization and
* type instantiation.
*/
public class CPPTemplates {
// The three constants below are used as special return values for the various overloads
// of CPPTemplates.determinePackSize() and for ICPPEvaluation.determinePackSize(), which
// search a type, template argument, or value for a usage of a template parameter pack
// and return the number of arguments bound to that parameter pack in an
// ICPPTemplateParameterMap.
// Used to indicate that the parameter pack is not bound to any arguments in the
// template parameter map. Computation of the pack size needs to be deferred until
// arguments for it become available.
static final int PACK_SIZE_DEFER = -1;
// Used to indicate that two different packs with different sizes were found.
static final int PACK_SIZE_FAIL = -2;
// Used to indicate that no template parameter packs were found.
static final int PACK_SIZE_NOT_FOUND = Integer.MAX_VALUE;
static enum TypeSelection { PARAMETERS, RETURN_TYPE, PARAMETERS_AND_RETURN_TYPE }
// Infrastructure to protect against rogue template metaprograms that don't terminate.
private static final int TEMPLATE_INSTANTIATION_DEPTH_LIMIT = 256;
private static final ThreadLocal<Integer> fTemplateInstantiationDepth = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
private static final ThreadLocal<Set<TypeInstantiationRequest>> instantiationsInProgress =
new ThreadLocal<Set<TypeInstantiationRequest>>() {
@Override
protected Set<TypeInstantiationRequest> initialValue() {
return new HashSet<>();
}
};
/**
* Instantiates a class or variable template with the given arguments. May return {@code null}.
*/
public static IBinding instantiate(ICPPPartiallySpecializable template, ICPPTemplateArgument[] args, IASTNode point) {
return instantiate(template, args, false, false, point);
}
/**
* Instantiates a class template with the given arguments. May return {@code null}.
*/
private static IBinding instantiate(ICPPPartiallySpecializable template, ICPPTemplateArgument[] args,
boolean isDefinition, boolean isExplicitSpecialization, IASTNode point) {
try {
ICPPTemplateArgument[] arguments= SemanticUtil.getSimplifiedArguments(args);
// Add default arguments, if necessary.
arguments= addDefaultArguments(template, arguments, point);
if (arguments == null)
return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
if (template instanceof ICPPTemplateTemplateParameter || hasDependentArgument(arguments)) {
return deferredInstance(template, arguments, point);
}
if (template instanceof ICPPClassTemplatePartialSpecialization) {
return instantiatePartialSpecialization((ICPPClassTemplatePartialSpecialization) template,
arguments, isDefinition, null, point);
}
if (arguments == args) {
arguments= args.clone(); // The createParameterMap call may modify the arguments array.
}
CPPTemplateParameterMap map = createParameterMap(template, arguments, point);
if (map == null) {
return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
}
ICPPTemplateInstance prim= getInstance(template, arguments, isDefinition);
if (prim != null && (isExplicitSpecialization || prim.isExplicitSpecialization()))
return prim;
if (!isExplicitSpecialization) {
IBinding result= selectSpecialization(template, arguments, isDefinition, point);
if (result != null)
return result;
}
return instantiatePrimaryTemplate(template, arguments, new InstantiationContext(map, point),
isDefinition);
} catch (DOMException e) {
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(ICPPTemplateDefinition template, int id, IASTNode point) {
return new ProblemBinding(point, id, template.getNameCharArray());
}
static IBinding isUsedInClassTemplateScope(ICPPClassTemplate ct, IASTName name) {
try {
IScope scope= null;
IASTNode node= name;
while (node != null) {
if (node.getPropertyInParent() == IASTCompositeTypeSpecifier.TYPE_NAME)
return null;
if (node instanceof IASTFunctionDefinition) {
IASTName functionName= ASTQueries.findInnermostDeclarator(((IASTFunctionDefinition) node).getDeclarator()).getName().getLastName();
// 'name' may be inside the qualifier of a method name in a out-of-line method definition.
// In such a case, calling getContainingScope() on the method name will attempt to
// resolve the qualifier, which will attempt to resolve 'name', which will get into
// a recursion as 'name' is currently being resolved. Since an out-of-line method
// definition cannot be inside a template scope, we can accurately return null
// in this case.
if (functionName.getParent() instanceof ICPPASTQualifiedName
&& ASTQueries.isAncestorOf(functionName.getParent(), name)) {
return null;
}
scope= CPPVisitor.getContainingScope(functionName);
break;
}
if (node instanceof ICPPASTCompositeTypeSpecifier) {
scope= ((ICPPASTCompositeTypeSpecifier) node).getScope();
break;
}
node= node.getParent();
}
while (scope != null) {
if (scope instanceof ISemanticProblem)
return null;
if (scope instanceof ICPPClassScope) {
ICPPClassType b= ((ICPPClassScope) scope).getClassType();
if (b != null && ct.isSameType(b)) {
return ct;
}
if (b instanceof ICPPClassTemplatePartialSpecialization) {
ICPPClassTemplatePartialSpecialization pspec= (ICPPClassTemplatePartialSpecialization) b;
if (ct.isSameType(pspec.getPrimaryClassTemplate())) {
return pspec;
}
} else if (b instanceof ICPPClassSpecialization) {
ICPPClassSpecialization specialization= (ICPPClassSpecialization) b;
if (ct.isSameType(specialization.getSpecializedBinding())) {
return specialization; }
}
}
if (scope instanceof IASTInternalScope) {
IASTInternalScope internalScope= (IASTInternalScope) scope;
IASTNode physicalNode = internalScope.getPhysicalNode();
if (physicalNode instanceof ICPPASTCompositeTypeSpecifier &&
((ICPPASTCompositeTypeSpecifier) physicalNode).getName() instanceof ICPPASTQualifiedName) {
scope= scope.getParent();
} else {
scope= CPPVisitor.getContainingScope(physicalNode);
if (scope == internalScope)
return null;
}
} else {
scope= scope.getParent();
}
}
} catch (DOMException e) {
}
return null;
}
private static IBinding instantiateFunctionTemplate(ICPPFunctionTemplate template,
ICPPTemplateArgument[] arguments, CPPTemplateParameterMap tpMap, IASTNode point)
throws DOMException {
ICPPTemplateInstance instance= getInstance(template, arguments, false);
if (instance != null) {
return instance;
}
IBinding owner= template.getOwner();
instance = createInstance(owner, template, tpMap, arguments, point);
if (instance instanceof ICPPFunction && SemanticUtil.isValidType(((ICPPFunction) instance).getType())) {
addInstance(template, arguments, instance);
}
return instance;
}
/**
* Instantiates a partial class template specialization.
*/
private static IBinding instantiatePartialSpecialization(ICPPPartialSpecialization partialSpec,
ICPPTemplateArgument[] args, boolean isDef, CPPTemplateParameterMap tpMap, IASTNode point)
throws DOMException {
ICPPTemplateInstance instance= getInstance(partialSpec, args, isDef);
if (instance != null)
return instance;
if (tpMap == null) {
tpMap = new CPPTemplateParameterMap(args.length);
if (!TemplateArgumentDeduction.fromTemplateArguments(partialSpec.getTemplateParameters(),
partialSpec.getTemplateArguments(), args, tpMap, point)) {
return null;
}
}
instance= createInstance(partialSpec.getOwner(), partialSpec, tpMap, args, point);
addInstance(partialSpec, args, instance);
return instance;
}
/**
* Instantiates the selected template, without looking for specializations.
* May return {@code null}.
*/
private static IBinding instantiatePrimaryTemplate(ICPPPartiallySpecializable template,
ICPPTemplateArgument[] arguments, InstantiationContext context, boolean isDef) throws DOMException {
assert !(template instanceof ICPPClassTemplatePartialSpecialization);
ICPPTemplateInstance instance= getInstance(template, arguments, isDef);
if (instance != null) {
return instance;
}
IBinding owner= template.getOwner();
instance = createInstance(owner, template, context.getParameterMap(), arguments, context.getPoint());
addInstance(template, arguments, instance);
return instance;
}
/**
* Obtains a cached instance from the template.
*/
private static ICPPTemplateInstance getInstance(ICPPTemplateDefinition template,
ICPPTemplateArgument[] args, boolean forDefinition) {
if (template instanceof ICPPInstanceCache) {
ICPPTemplateInstance result = ((ICPPInstanceCache) template).getInstance(args);
if (forDefinition && result instanceof IIndexBinding)
return null;
if (result != null && !result.isExplicitSpecialization()) {
// Don't use the cached instance if its argument is an index type and the requested
// argument is an AST type. Despite identical signatures the types may be different.
ICPPTemplateArgument[] instanceArgs = result.getTemplateArguments();
for (int i = 0; i < args.length; i++) {
if (!(args[i].getTypeValue() instanceof IIndexType) &&
(instanceArgs[i].getTypeValue() instanceof IIndexType)) {
return null;
}
}
}
return result;
}
return null;
}
/**
* Caches an instance with the template.
*/
private static void addInstance(ICPPTemplateDefinition template, ICPPTemplateArgument[] args, ICPPTemplateInstance instance) {
if (template instanceof ICPPInstanceCache) {
((ICPPInstanceCache) template).addInstance(args, instance);
}
}
private static IBinding deferredInstance(ICPPPartiallySpecializable template,
ICPPTemplateArgument[] arguments, IASTNode point) throws DOMException {
ICPPTemplateInstance instance= getInstance(template, arguments, false);
if (instance != null)
return instance;
if (template instanceof ICPPClassTemplate) {
instance = new CPPDeferredClassInstance((ICPPClassTemplate) template, arguments);
addInstance(template, arguments, instance);
}
if (template instanceof ICPPVariableTemplate) {
instance = new CPPDeferredVariableInstance((ICPPVariableTemplate) template, arguments);
addInstance(template, arguments, instance);
}
return instance;
}
private static ICPPTemplateArgument[] addDefaultArguments(ICPPTemplateDefinition template,
ICPPTemplateArgument[] arguments, IASTNode point) throws DOMException {
if (template instanceof ICPPClassTemplatePartialSpecialization)
return arguments;
boolean havePackExpansion= false;
for (int i = 0; i < arguments.length; i++) {
ICPPTemplateArgument arg = arguments[i];
if (arg.isPackExpansion()) {
if (i != arguments.length - 1) {
return arguments;
}
havePackExpansion= true;
}
}
ICPPTemplateParameter[] tpars = template.getTemplateParameters();
int tparCount = tpars.length;
final int argCount = arguments.length;
if (tparCount == argCount)
return arguments;
if (tparCount == 0)
return null;
// More arguments allowed if we have a parameter pack.
if (tparCount < argCount) {
if (tpars[tparCount - 1].isParameterPack())
return arguments;
if (havePackExpansion && tparCount + 1 == argCount)
return arguments;
return null;
}
// Fewer arguments are allowed with a pack expansion
if (havePackExpansion)
return arguments;
// Fewer arguments are allowed with default arguments
if (tpars[tparCount - 1].isParameterPack())
tparCount--;
if (tparCount == argCount)
return arguments;
ICPPTemplateArgument[] completeArgs= new ICPPTemplateArgument[tparCount];
CPPTemplateParameterMap map= new CPPTemplateParameterMap(tparCount);
InstantiationContext context = new InstantiationContext(map, point);
for (int i = 0; i < tparCount; i++) {
final ICPPTemplateParameter tpar = tpars[i];
if (tpar.isParameterPack()) {
// Parameter pack must be last template parameter.
return null;
}
ICPPTemplateArgument arg;
if (i < argCount) {
arg= arguments[i];
} else {
ICPPTemplateArgument defaultArg= tpar.getDefaultValue();
if (defaultArg == null) {
if (template instanceof ICPPInternalClassTemplate) {
defaultArg= ((ICPPInternalClassTemplate) template).getDefaultArgFromIndex(i);
}
}
if (defaultArg == null)
return null;
arg= instantiateArgument(defaultArg, context);
arg= SemanticUtil.getSimplifiedArgument(arg);
if (!isValidArgument(arg)) {
return null;
}
}
context.addToParameterMap(tpar, arg);
completeArgs[i]= arg;
}
return completeArgs;
}
public static ICPPDeferredClassInstance createDeferredInstance(ICPPClassTemplate ct) {
ICPPTemplateArgument[] args;
if (ct instanceof ICPPClassTemplatePartialSpecialization) {
args= ((ICPPClassTemplatePartialSpecialization) ct).getTemplateArguments();
} else {
args = templateParametersAsArguments(ct);
}
return new CPPDeferredClassInstance(ct, args, (ICPPScope) ct.getCompositeScope());
}
public static ICPPTemplateArgument[] templateParametersAsArguments(ICPPClassTemplate template) {
ICPPTemplateParameter[] tpars = template.getTemplateParameters();
ICPPTemplateArgument[] args;
args = new ICPPTemplateArgument[tpars.length];
for (int i = 0; i < tpars.length; i++) {
final ICPPTemplateParameter tp = tpars[i];
if (tp instanceof IType) {
IType t= (IType) tp;
if (tp.isParameterPack()) {
t= new CPPParameterPackType(t);
}
args[i] = new CPPTemplateTypeArgument(t);
} else if (tp instanceof ICPPTemplateNonTypeParameter) {
// Non-type template parameter pack already has type 'ICPPParameterPackType'
final ICPPTemplateNonTypeParameter nttp = (ICPPTemplateNonTypeParameter) tp;
args[i] = new CPPTemplateNonTypeArgument(DependentValue.create(template, nttp), nttp.getType());
} else {
assert false;
}
}
return args;
}
/**
* Extracts the IASTName of a template parameter.
*/
public static IASTName getTemplateParameterName(ICPPASTTemplateParameter param) {
if (param instanceof ICPPASTSimpleTypeTemplateParameter)
return ((ICPPASTSimpleTypeTemplateParameter) param).getName();
else if (param instanceof ICPPASTTemplatedTypeTemplateParameter)
return ((ICPPASTTemplatedTypeTemplateParameter) param).getName();
else if (param instanceof ICPPASTParameterDeclaration)
return ASTQueries.findInnermostDeclarator(((ICPPASTParameterDeclaration) param).getDeclarator()).getName();
return null;
}
public static ICPPTemplateDefinition getContainingTemplate(ICPPASTTemplateParameter param) {
IASTNode parent = param.getParent();
IBinding binding = null;
if (parent instanceof ICPPASTTemplateDeclaration) {
ICPPASTTemplateDeclaration[] templates = new ICPPASTTemplateDeclaration[] { (ICPPASTTemplateDeclaration) parent };
while (parent.getParent() instanceof ICPPASTTemplateDeclaration) {
parent = parent.getParent();
templates = ArrayUtil.append(ICPPASTTemplateDeclaration.class, templates, (ICPPASTTemplateDeclaration) parent);
}
templates = ArrayUtil.trim(ICPPASTTemplateDeclaration.class, templates);
ICPPASTTemplateDeclaration templateDeclaration = templates[0];
IASTDeclaration decl = templateDeclaration.getDeclaration();
while (decl instanceof ICPPASTTemplateDeclaration) {
decl = ((ICPPASTTemplateDeclaration) decl).getDeclaration();
}
IASTName name = null;
if (decl instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDecl = (IASTSimpleDeclaration) decl;
IASTDeclarator[] dtors = ((IASTSimpleDeclaration) decl).getDeclarators();
if (dtors.length == 0) {
IASTDeclSpecifier spec = simpleDecl.getDeclSpecifier();
if (spec instanceof ICPPASTCompositeTypeSpecifier) {
name = ((ICPPASTCompositeTypeSpecifier) spec).getName();
} else if (spec instanceof ICPPASTElaboratedTypeSpecifier) {
name = ((ICPPASTElaboratedTypeSpecifier) spec).getName();
}
} else {
IASTDeclarator dtor = dtors[0];
dtor= ASTQueries.findInnermostDeclarator(dtor);
name = dtor.getName();
}
} else if (decl instanceof IASTFunctionDefinition) {
IASTDeclarator dtor = ((IASTFunctionDefinition) decl).getDeclarator();
dtor= ASTQueries.findInnermostDeclarator(dtor);
name = dtor.getName();
} else if (decl instanceof ICPPASTAliasDeclaration) {
name = ((ICPPASTAliasDeclaration) decl).getAlias();
}
if (name == null)
return null;
if (name instanceof ICPPASTQualifiedName) {
int idx = templates.length;
int i = 0;
ICPPASTNameSpecifier[] qualifier = ((ICPPASTQualifiedName) name).getQualifier();
for (ICPPASTNameSpecifier element : qualifier) {
if (element instanceof ICPPASTTemplateId) {
++i;
if (i == idx) {
binding = ((ICPPASTTemplateId) element).resolveBinding();
break;
}
}
}
if (binding == null)
binding = name.getLastName().resolveBinding();
} else {
binding = name.resolveBinding();
}
} else if (parent instanceof ICPPASTTemplatedTypeTemplateParameter) {
ICPPASTTemplatedTypeTemplateParameter templatedParam = (ICPPASTTemplatedTypeTemplateParameter) parent;
binding = templatedParam.getName().resolveBinding();
}
return (binding instanceof ICPPTemplateDefinition) ? (ICPPTemplateDefinition) binding : null;
}
public static IBinding createBinding(ICPPASTTemplateParameter tp) {
if (tp instanceof ICPPASTSimpleTypeTemplateParameter) {
return new CPPTemplateTypeParameter(((ICPPASTSimpleTypeTemplateParameter) tp).getName(), tp.isParameterPack());
}
if (tp instanceof ICPPASTTemplatedTypeTemplateParameter) {
return new CPPTemplateTemplateParameter(((ICPPASTTemplatedTypeTemplateParameter) tp).getName(), tp.isParameterPack());
}
assert tp instanceof ICPPASTParameterDeclaration;
final IASTDeclarator dtor = ((ICPPASTParameterDeclaration) tp).getDeclarator();
return new CPPTemplateNonTypeParameter(ASTQueries.findInnermostDeclarator(dtor).getName());
}
public static IBinding createBinding(ICPPASTTemplateId id) {
if (!isClassTemplate(id)) {
// Functions are instantiated as part of the resolution process.
IBinding result= CPPVisitor.createBinding(id);
IASTName templateName = id.getTemplateName();
if (result instanceof ICPPClassTemplate || result instanceof ICPPAliasTemplate
|| result instanceof ICPPVariableTemplate) {
templateName.setBinding(result);
id.setBinding(null);
} else {
if (result instanceof ICPPTemplateInstance) {
templateName.setBinding(((ICPPTemplateInstance) result).getTemplateDefinition());
} else {
templateName.setBinding(result);
}
return result;
}
}
IASTNode parentOfName = id.getParent();
boolean isLastName= true;
if (parentOfName instanceof ICPPASTQualifiedName) {
isLastName= ((ICPPASTQualifiedName) parentOfName).getLastName() == id;
parentOfName = parentOfName.getParent();
}
boolean isDeclaration= false;
boolean isDefinition= false;
boolean isExplicitSpecialization= false;
if (isLastName && parentOfName != null) {
IASTNode declaration= parentOfName.getParent();
if (declaration instanceof IASTSimpleDeclaration) {
if (parentOfName instanceof ICPPASTElaboratedTypeSpecifier) {
isDeclaration= true;
} else if (parentOfName instanceof ICPPASTCompositeTypeSpecifier) {
isDefinition= true;
} else if (parentOfName instanceof ICPPASTDeclarator) {
isDeclaration= true;
}
if (isDeclaration || isDefinition) {
IASTNode parentOfDeclaration = declaration.getParent();
if (parentOfDeclaration instanceof ICPPASTExplicitTemplateInstantiation) {
isDeclaration= false;
} else if (parentOfDeclaration instanceof ICPPASTTemplateSpecialization) {
isExplicitSpecialization= true;
}
}
}
}
try {
IBinding result= null;
IASTName templateName = id.getTemplateName();
IBinding template = templateName.resolvePreBinding();
while (template instanceof CPPTypedefSpecialization) {
template = ((CPPTypedefSpecialization) template).getSpecializedBinding();
}
// Alias template.
if (template instanceof ICPPAliasTemplate) {
ICPPAliasTemplate aliasTemplate = (ICPPAliasTemplate) template;
ICPPTemplateArgument[] args = createTemplateArgumentArray(id);
return instantiateAliasTemplate(aliasTemplate, args, id);
}
// Alias template instance.
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;
ICPPTemplateArgument[] args = createTemplateArgumentArray(id);
return instantiateAliasTemplateInstance(aliasTemplateInstance, args, id);
}
// Class or variable template.
if (template instanceof ICPPConstructor) {
template= template.getOwner();
}
if (template instanceof ICPPUnknownMemberClass) {
IType owner= ((ICPPUnknownMemberClass) template).getOwnerType();
ICPPTemplateArgument[] args= createTemplateArgumentArray(id);
args= SemanticUtil.getSimplifiedArguments(args);
return new CPPUnknownClassInstance(owner, id.getSimpleID(), args);
}
if (!(template instanceof ICPPPartiallySpecializable) || template instanceof ICPPClassTemplatePartialSpecialization)
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TYPE, templateName.toCharArray());
final ICPPPartiallySpecializable classTemplate = (ICPPPartiallySpecializable) template;
ICPPTemplateArgument[] args= createTemplateArgumentArray(id);
if (hasDependentArgument(args)) {
ICPPASTTemplateDeclaration tdecl= getTemplateDeclaration(id);
if (tdecl != null) {
if (argsAreTrivial(classTemplate.getTemplateParameters(), args)) {
result= classTemplate;
} else {
args= addDefaultArguments(classTemplate, args, id);
if (args == null) {
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, templateName.toCharArray());
}
ICPPPartialSpecialization partialSpec= findPartialSpecialization(classTemplate, args);
ICPPClassTemplatePartialSpecialization indexSpec = null;
if ((isDeclaration || isDefinition) &&
(partialSpec instanceof ICPPClassTemplatePartialSpecialization)) {
indexSpec = (ICPPClassTemplatePartialSpecialization) partialSpec;
partialSpec = null;
}
if (partialSpec == null) {
if (isDeclaration || isDefinition) {
if (template instanceof ICPPClassTemplate) {
partialSpec = new CPPClassTemplatePartialSpecialization(id, args);
if (indexSpec != null) {
SemanticUtil.recordPartialSpecialization(indexSpec,
(ICPPClassTemplatePartialSpecialization) partialSpec, id);
} else if (template instanceof ICPPInternalClassTemplate) {
((ICPPInternalClassTemplate) template).addPartialSpecialization(
(ICPPClassTemplatePartialSpecialization) partialSpec);
}
} else if (template instanceof ICPPVariableTemplate) {
if (template instanceof ICPPFieldTemplate) {
partialSpec = new CPPFieldTemplatePartialSpecialization(id, args);
} else {
partialSpec = new CPPVariableTemplatePartialSpecialization(id, args);
}
if (template instanceof CPPVariableTemplate)
((CPPVariableTemplate) template).addPartialSpecialization(partialSpec);
}
return partialSpec;
}
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TYPE, templateName.toCharArray());
}
result= partialSpec;
}
}
}
if (result == null) {
result= instantiate(classTemplate, args, isDefinition, isExplicitSpecialization, id);
if (result instanceof ICPPInternalBinding) {
if (isDeclaration) {
ASTInternal.addDeclaration(result, id);
} else if (isDefinition) {
ASTInternal.addDefinition(result, id);
}
}
}
return CPPSemantics.postResolution(result, id);
} catch (DOMException e) {
return e.getProblem();
}
}
private static IBinding createAliasTemplaceInstance(ICPPAliasTemplate aliasTemplate,
ICPPTemplateArgument[] args, ICPPTemplateParameterMap parameterMap, IType aliasedType,
IBinding owner, IASTNode point) {
InstantiationContext context = createInstantiationContext(parameterMap, owner, point);
IType instantiatedType = instantiateType(aliasedType, context);
StringBuilder buf= new StringBuilder();
buf.append(aliasTemplate.getName()).append(ASTTypeUtil.getArgumentListString(args, false));
char[] name = new char[buf.length()];
buf.getChars(0, buf.length(), name, 0);
return new CPPAliasTemplateInstance(name, aliasTemplate, instantiatedType);
}
static boolean isClassTemplate(ICPPASTTemplateId id) {
IASTNode parentOfName = id.getParent();
if (parentOfName instanceof ICPPASTQualifiedName) {
if (((ICPPASTQualifiedName) parentOfName).getLastName() != id)
return true;
parentOfName= parentOfName.getParent();
}
if (parentOfName instanceof ICPPASTElaboratedTypeSpecifier ||
parentOfName instanceof ICPPASTCompositeTypeSpecifier ||
parentOfName instanceof ICPPASTNamedTypeSpecifier ||
parentOfName instanceof ICPPASTBaseSpecifier) {
return true;
}
if (parentOfName instanceof IASTDeclarator) {
IASTDeclarator rel= ASTQueries.findTypeRelevantDeclarator((IASTDeclarator) parentOfName);
return !(rel instanceof IASTFunctionDeclarator);
}
return false;
}
public static ICPPTemplateInstance createInstance(IBinding owner, ICPPTemplateDefinition template,
ICPPTemplateParameterMap tpMap, ICPPTemplateArgument[] args, IASTNode point) {
if (owner instanceof ICPPSpecialization) {
ICPPTemplateParameterMap map= ((ICPPSpecialization) owner).getTemplateParameterMap();
if (map != null) {
((CPPTemplateParameterMap) tpMap).putAll(map);
}
}
ICPPTemplateInstance instance = null;
if (template instanceof ICPPClassType) {
instance = new CPPClassInstance((ICPPClassType) template, owner, tpMap, args);
} else if (template instanceof ICPPFunction) {
ICPPFunction func= (ICPPFunction) template;
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
ICPPFunctionType type= (ICPPFunctionType) instantiateType(func.getType(), context);
IType[] exceptionSpecs= instantiateTypes(func.getExceptionSpecification(), context);
CPPFunctionSpecialization spec;
if (owner instanceof ICPPClassType && template instanceof ICPPMethod) {
if (template instanceof ICPPConstructor) {
spec = new CPPConstructorInstance((ICPPConstructor) template, (ICPPClassType) owner,
context.getParameterMap(), args, type, exceptionSpecs);
} else {
spec = new CPPMethodInstance((ICPPMethod) template, (ICPPClassType) owner,
context.getParameterMap(), args, type, exceptionSpecs);
}
} else {
spec = new CPPFunctionInstance((ICPPFunction) template, owner, tpMap, args, type, exceptionSpecs);
}
spec.setParameters(specializeParameters(func.getParameters(), spec, context, IntegralValue.MAX_RECURSION_DEPTH));
instance = (ICPPTemplateInstance) spec;
} else if (template instanceof ICPPVariable) {
ICPPVariable var = (ICPPVariable) template;
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
IType type = instantiateType(var.getType(), context);
IValue value;
ICPPASTDeclarator decl = ASTQueries.findAncestorWithType(point, ICPPASTDeclarator.class);
if (((IASTName) point).getRoleOfName(false) == IASTNameOwner.r_definition
&& decl != null && decl.getInitializer() != null) {
// Explicit specialization.
value = SemanticUtil.getValueOfInitializer(decl.getInitializer(), type);
} else {
value = instantiateValue(var.getInitialValue(), context, IntegralValue.MAX_RECURSION_DEPTH);
}
if (template instanceof ICPPField) {
instance = new CPPFieldInstance(template, owner, tpMap, args, type, value);
} else {
instance = new CPPVariableInstance(template, owner, tpMap, args, type, value);
}
}
return instance;
}
public static ICPPParameter[] specializeParameters(ICPPParameter[] parameters, ICPPFunction functionSpec,
InstantiationContext context, int maxdepth) {
if (parameters.length == 0) {
return parameters;
}
// Because of parameter packs there can be more or less parameters in the specialization
IType[] specializedParameterTypes = functionSpec.getType().getParameterTypes();
final int length = specializedParameterTypes.length;
ICPPParameter par = null;
ICPPParameter[] result = new ICPPParameter[length];
for (int i = 0; i < length; i++) {
if (i < parameters.length) {
par = parameters[i];
} // else reuse last parameter (which should be a pack)
@SuppressWarnings("null")
IValue defaultValue = par.getDefaultValue();
IValue specializedValue = instantiateValue(defaultValue, context, maxdepth);
result[i] = new CPPParameterSpecialization(par, functionSpec, specializedParameterTypes[i],
specializedValue, context.getParameterMap());
}
return result;
}
// TODO(nathanridge): Handle this as a case in createSpecialization()
public static ICPPVariable createVariableSpecialization(InstantiationContext context, ICPPVariable variable) {
final IType type = variable.getType();
final IType newType = instantiateType(type, context);
final IValue value = variable.getInitialValue();
final IValue newValue = instantiateValue(value, context, IntegralValue.MAX_RECURSION_DEPTH);
if (type == newType && value == newValue) {
return variable;
}
ICPPVariable newVariable = new CPPVariableSpecialization(variable, context.getContextSpecialization(),
context.getParameterMap(), newType, newValue);
context.putInstantiatedLocal(variable, newVariable);
return newVariable;
}
public static IBinding createSpecialization(ICPPSpecialization owner, IBinding decl, IASTNode point) {
IBinding spec = null;
final ICPPTemplateParameterMap tpMap= owner.getTemplateParameterMap();
final ICPPClassSpecialization classOwner = (owner instanceof ICPPClassSpecialization) ? (ICPPClassSpecialization) owner : null;
// Guard against infinite recursion during template instantiation with a depth limit.
int instantiationDepth = fTemplateInstantiationDepth.get();
if (instantiationDepth > TEMPLATE_INSTANTIATION_DEPTH_LIMIT) {
return RecursionResolvingBinding.createFor(decl, point);
}
// Increment the instantiation depth for the duration of this call.
fTemplateInstantiationDepth.set(instantiationDepth + 1);
try {
if (decl instanceof ICPPClassTemplatePartialSpecialization && classOwner != null) {
try {
ICPPClassTemplatePartialSpecialization pspec= (ICPPClassTemplatePartialSpecialization) decl;
ICPPClassTemplate template= pspec.getPrimaryClassTemplate();
ICPPTemplateArgument[] args = pspec.getTemplateArguments();
template= (ICPPClassTemplate) classOwner.specializeMember(template, point);
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
args= instantiateArguments(args, context, false);
spec= new CPPClassTemplatePartialSpecializationSpecialization(pspec, tpMap, template, args);
} catch (DOMException e) {
}
} else if (decl instanceof ICPPClassTemplate && classOwner != null) {
ICPPClassTemplate template = (ICPPClassTemplate) decl;
CPPClassTemplateSpecialization classTemplateSpec = new CPPClassTemplateSpecialization(template, classOwner, tpMap);
classTemplateSpec.setTemplateParameters(specializeTemplateParameters(classTemplateSpec,
(ICPPScope) classTemplateSpec.getScope(), template.getTemplateParameters(), classOwner, point));
spec = classTemplateSpec;
} else if (decl instanceof ICPPClassType && classOwner != null) {
// TODO: Handle local classes
IBinding oldOwner = decl.getOwner();
if (oldOwner instanceof IType && classOwner.getSpecializedBinding().isSameType((IType) oldOwner)) {
spec = new CPPClassSpecialization((ICPPClassType) decl, owner, tpMap);
} else {
spec = new CPPClassSpecialization((ICPPClassType) decl, oldOwner, tpMap);
}
} else if (decl instanceof ICPPField && classOwner != null) {
ICPPField field= (ICPPField) decl;
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
IType type= instantiateType(field.getType(), context);
IValue value= instantiateValue(field.getInitialValue(), context, IntegralValue.MAX_RECURSION_DEPTH);
if (decl instanceof ICPPFieldTemplate) {
CPPFieldTemplateSpecialization fieldTempSpec = new CPPFieldTemplateSpecialization(decl,
classOwner, tpMap, type, value);
ICPPTemplateParameter[] params = specializeTemplateParameters(fieldTempSpec,
(ICPPScope) fieldTempSpec.getScope(),
((ICPPFieldTemplate) decl).getTemplateParameters(), classOwner, point);
fieldTempSpec.setTemplateParameters(params);
spec = fieldTempSpec;
} else {
spec = new CPPFieldSpecialization(decl, classOwner, tpMap, type, value);
}
} else if (decl instanceof ICPPFunction) {
ICPPFunction func= (ICPPFunction) decl;
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
ICPPFunctionType type= (ICPPFunctionType) instantiateType(func.getType(), context);
IType[] exceptionSpecs= instantiateTypes(func.getExceptionSpecification(), context);
CPPFunctionSpecialization functionSpec = null;
if (decl instanceof ICPPFunctionTemplate) {
if (decl instanceof ICPPMethod && classOwner != null) {
CPPMethodTemplateSpecialization methodSpec;
if (decl instanceof ICPPConstructor) {
methodSpec = new CPPConstructorTemplateSpecialization((ICPPConstructor) decl,
classOwner, tpMap, type, exceptionSpecs);
} else {
methodSpec = new CPPMethodTemplateSpecialization((ICPPMethod) decl, classOwner, tpMap,
type, exceptionSpecs);
}
methodSpec.setTemplateParameters(specializeTemplateParameters(methodSpec,
(ICPPScope) methodSpec.getScope(),
((ICPPFunctionTemplate) decl).getTemplateParameters(), classOwner, point));
functionSpec = methodSpec;
} else {
IBinding oldOwner = decl.getOwner();
functionSpec = new CPPFunctionTemplateSpecialization((ICPPFunctionTemplate) decl,
oldOwner, tpMap, type, exceptionSpecs);
}
} else if (decl instanceof ICPPConstructor && classOwner != null) {
functionSpec = new CPPConstructorSpecialization((ICPPConstructor) decl, classOwner, tpMap, type, exceptionSpecs);
} else if (decl instanceof ICPPMethod && classOwner != null) {
functionSpec = new CPPMethodSpecialization((ICPPMethod) decl, classOwner, tpMap, type, exceptionSpecs);
} else if (decl instanceof ICPPFunction) {
if (type.isSameType(func.getType())) {
// There is no need to create a CPPFunctionSpecialization object since the function is
// a friend function with the type that is not affected by the specialization.
// See http://bugs.eclipse.org/513681
spec = func;
} else {
IBinding oldOwner = decl.getOwner();
functionSpec = new CPPFunctionSpecialization(func, oldOwner, tpMap, type, exceptionSpecs);
}
}
if (functionSpec != null) {
functionSpec.setParameters(specializeParameters(func.getParameters(), functionSpec, context,
IntegralValue.MAX_RECURSION_DEPTH));
spec = functionSpec;
}
} else if (decl instanceof ITypedef) {
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
IType type= instantiateType(((ITypedef) decl).getType(), context);
spec = new CPPTypedefSpecialization(decl, owner, tpMap, type);
} else if (decl instanceof ICPPAliasTemplate) {
ICPPAliasTemplate aliasTemplate = (ICPPAliasTemplate) decl;
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
IType type= instantiateType(aliasTemplate.getType(), context);
spec = new CPPAliasTemplateInstance(decl.getNameCharArray(), aliasTemplate, type);
} else if (decl instanceof ICPPEnumeration && classOwner != null) {
// TODO: Handle local enumerations
spec = CPPEnumerationSpecialization.createInstance((ICPPEnumeration) decl, classOwner, tpMap, point);
} else if (decl instanceof IEnumerator && classOwner != null) {
IEnumerator enumerator = (IEnumerator) decl;
ICPPEnumeration enumeration = (ICPPEnumeration) enumerator.getOwner();
IBinding enumSpec = classOwner.specializeMember(enumeration, point);
if (enumSpec instanceof ICPPEnumerationSpecialization) {
spec = ((ICPPEnumerationSpecialization) enumSpec).specializeEnumerator(enumerator);
}
} else if (decl instanceof ICPPUsingDeclaration) {
IBinding[] delegates= ((ICPPUsingDeclaration) decl).getDelegates();
List<IBinding> result= new ArrayList<>();
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
for (IBinding delegate : delegates) {
try {
if (delegate instanceof ICPPUnknownBinding) {
delegate= resolveUnknown((ICPPUnknownBinding) delegate, context);
}
if (delegate instanceof CPPFunctionSet) {
for (IBinding b : ((CPPFunctionSet) delegate).getBindings()) {
result.add(b);
}
} else if (delegate != null) {
result.add(delegate);
}
} catch (DOMException e) {
}
}
delegates= result.toArray(new IBinding[result.size()]);
spec= new CPPUsingDeclarationSpecialization((ICPPUsingDeclaration) decl, owner, tpMap, delegates);
}
} catch (DOMException e) {
CCorePlugin.log(e);
} finally {
// Restore original instantiation depth.
fTemplateInstantiationDepth.set(instantiationDepth);
}
return spec;
}
private static InstantiationContext createInstantiationContext(ICPPTemplateParameterMap tpMap,
IBinding owner, IASTNode point) {
return new InstantiationContext(tpMap, getSpecializationContext(owner), point);
}
public static ICPPClassSpecialization getSpecializationContext(IBinding owner) {
ICPPClassSpecialization within = getContextClassSpecialization(owner);
if (within == null)
return null;
ICPPClassType orig = within.getSpecializedBinding();
while (true) {
IBinding o1 = within.getOwner();
IBinding o2 = orig.getOwner();
if (!(o1 instanceof ICPPClassSpecialization && o2 instanceof ICPPClassType))
return within;
ICPPClassSpecialization nextWithin = (ICPPClassSpecialization) o1;
orig= (ICPPClassType) o2;
if (orig.isSameType(nextWithin))
return within;
within= nextWithin;
}
}
public static IValue instantiateValue(IValue value, InstantiationContext context, int maxDepth) {
if (value == null)
return null;
ICPPEvaluation evaluation = value.getEvaluation();
if (evaluation == null)
return value;
ICPPEvaluation instantiated = evaluation.instantiate(context, maxDepth);
if (instantiated == evaluation)
return value;
return instantiated.getValue(context.getPoint());
}
public static boolean containsParameterPack(IType type) {
return determinePackSize(type, CPPTemplateParameterMap.EMPTY) == PACK_SIZE_DEFER;
}
static int determinePackSize(IType type, ICPPTemplateParameterMap tpMap) {
if (type instanceof ICPPFunctionType) {
final ICPPFunctionType ft = (ICPPFunctionType) type;
final IType rt = ft.getReturnType();
int r = determinePackSize(rt, tpMap);
if (r < 0)
return r;
IType[] ps = ft.getParameterTypes();
for (IType pt : ps) {
r= combinePackSize(r, determinePackSize(pt, tpMap));
if (r < 0)
return r;
}
return r;
}
if (type instanceof ICPPTemplateParameter) {
return determinePackSize((ICPPTemplateParameter) type, tpMap);
}
if (type instanceof TypeOfDependentExpression) {
return ((TypeOfDependentExpression) type).getEvaluation().determinePackSize(tpMap);
}
if (type instanceof ICPPUnknownBinding) {
return determinePackSize((ICPPUnknownBinding) type, tpMap);
}
if (type instanceof ICPPParameterPackType)
return PACK_SIZE_NOT_FOUND;
int r= PACK_SIZE_NOT_FOUND;
if (type instanceof IArrayType) {
IArrayType at= (IArrayType) type;
IValue asize= at.getSize();
r= determinePackSize(asize, tpMap);
if (r < 0)
return r;
}
if (type instanceof ITypeContainer) {
final ITypeContainer typeContainer = (ITypeContainer) type;
r= combinePackSize(r, determinePackSize(typeContainer.getType(), tpMap));
}
return r;
}
static int determinePackSize(ICPPTemplateParameter tpar, ICPPTemplateParameterMap tpMap) {
if (tpar.isParameterPack()) {
ICPPTemplateArgument[] args= tpMap.getPackExpansion(tpar);
if (args != null)
return args.length;
return PACK_SIZE_DEFER;
}
return PACK_SIZE_NOT_FOUND;
}
static int determinePackSize(ICPPUnknownBinding binding, ICPPTemplateParameterMap tpMap) {
int r= PACK_SIZE_NOT_FOUND;
if (binding instanceof ICPPDeferredClassInstance) {
ICPPDeferredClassInstance dcl= (ICPPDeferredClassInstance) binding;
if (dcl.getClassTemplate() instanceof ICPPTemplateTemplateParameter) {
r = combinePackSize(r, determinePackSize((ICPPTemplateParameter) dcl.getClassTemplate(),
tpMap));
}
ICPPTemplateArgument[] args = dcl.getTemplateArguments();
for (ICPPTemplateArgument arg : args) {
r= combinePackSize(r, determinePackSize(arg, tpMap));
if (r < 0)
return r;
}
}
IBinding ownerBinding= binding.getOwner();
if (ownerBinding instanceof IType)
r= combinePackSize(r, determinePackSize((IType) ownerBinding, tpMap));
return r;
}
static int determinePackSize(IValue value, ICPPTemplateParameterMap tpMap) {
ICPPEvaluation eval = value.getEvaluation();
if (eval == null)
return PACK_SIZE_NOT_FOUND;
return ((CPPEvaluation) eval).determinePackSize(tpMap);
}
static int determinePackSize(ICPPTemplateArgument arg, ICPPTemplateParameterMap tpMap) {
if (arg.isTypeValue())
return determinePackSize(arg.getTypeValue(), tpMap);
return determinePackSize(arg.getNonTypeValue(), tpMap);
}
static int combinePackSize(int ps1, int ps2) {
if (ps1 < 0 || ps2 == PACK_SIZE_NOT_FOUND)
return ps1;
if (ps2 < 0 || ps1 == PACK_SIZE_NOT_FOUND)
return ps2;
if (ps1 != ps2)
return PACK_SIZE_FAIL;
return ps1;
}
/**
* Instantiates types contained in an array.
*
* @param types an array of types
* @param context the template instantiation context
* @return an array containing instantiated types.
*/
public static IType[] instantiateTypes(IType[] types, InstantiationContext context) {
if (types == null)
return null;
// Don't create a new array until it's really needed.
IType[] result = types;
int j= 0;
for (int i = 0; i < types.length; i++) {
IType origType = types[i];
IType newType;
if (origType instanceof ICPPParameterPackType) {
IType innerType= ((ICPPParameterPackType) origType).getType();
int packSize= determinePackSize(innerType, context.getParameterMap());
if (packSize == PACK_SIZE_FAIL || packSize == PACK_SIZE_NOT_FOUND) {
newType= new ProblemBinding(context.getPoint(), IProblemBinding.SEMANTIC_INVALID_TYPE,
types[i] instanceof IBinding ? ((IBinding) types[i]).getNameCharArray() : null);
} else if (packSize == PACK_SIZE_DEFER) {
newType= origType;
} else {
IType[] newResult= new IType[result.length + packSize - 1];
System.arraycopy(result, 0, newResult, 0, j);
result= newResult;
int oldPackOffset = context.getPackOffset();
for (int k= 0; k < packSize; k++) {
context.setPackOffset(k);
result[j++]= instantiateType(innerType, context);
}
context.setPackOffset(oldPackOffset);
continue;
}
} else {
newType = instantiateType(origType, context);
}
if (result != types) {
result[j++]= newType;
} else {
if (newType != origType) {
result = new IType[types.length];
System.arraycopy(types, 0, result, 0, i);
result[j]= newType;
}
j++;
}
}
return result;
}
/**
* Instantiates arguments contained in an array. Instantiated arguments are checked for
* validity. If the {@code strict} parameter is {@code true}, the method returns {@code null} if
* any of the instantiated arguments are invalid. If the {@code strict} parameter is
* {@code false}, any invalid instantiated arguments are replaced by the corresponding original
* arguments.
*/
public static ICPPTemplateArgument[] instantiateArguments(ICPPTemplateArgument[] args, InstantiationContext context, boolean strict) throws DOMException {
// Don't create a new array until it's really needed.
ICPPTemplateArgument[] result = args;
int resultShift= 0;
for (int i = 0; i < args.length; i++) {
ICPPTemplateArgument origArg = args[i];
ICPPTemplateArgument newArg;
if (origArg.isPackExpansion()) {
ICPPTemplateArgument pattern= origArg.getExpansionPattern();
int packSize= determinePackSize(pattern, context.getParameterMap());
if (packSize == PACK_SIZE_FAIL || packSize == PACK_SIZE_NOT_FOUND) {
throw new DOMException(new ProblemBinding(context.getPoint(),
IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, null));
} else if (packSize == PACK_SIZE_DEFER) {
newArg= origArg;
} else {
int shift = packSize - 1;
ICPPTemplateArgument[] newResult= new ICPPTemplateArgument[args.length + resultShift + shift];
System.arraycopy(result, 0, newResult, 0, i + resultShift);
context.setExpandPack(true);
int oldPackOffset = context.getPackOffset();
for (int j= 0; j < packSize; j++) {
context.setPackOffset(j);
newArg = instantiateArgument(pattern, context);
if (!isValidArgument(newArg)) {
if (strict)
return null;
result[i + resultShift] = origArg;
newResult = result;
shift = 0;
break;
}
if (context.isPackExpanded()) {
IType type = newArg.getTypeValue();
if (type != null) {
type = new CPPParameterPackType(type);
newArg = new CPPTemplateTypeArgument(type);
}
context.setPackExpanded(false);
}
newResult[i + resultShift + j]= newArg;
}
context.setPackOffset(oldPackOffset);
context.setExpandPack(false);
result= newResult;
resultShift += shift;
continue;
}
} else {
newArg = instantiateArgument(origArg, context);
if (!isValidArgument(newArg)) {
if (strict)
return null;
newArg = origArg;
}
}
if (result != args) {
result[i + resultShift]= newArg;
} else if (newArg != origArg) {
assert resultShift == 0;
result = new ICPPTemplateArgument[args.length];
if (i > 0) {
System.arraycopy(args, 0, result, 0, i);
}
result[i]= newArg;
}
}
return result;
}
/**
* Instantiates a template argument.
*/
static ICPPTemplateArgument instantiateArgument(ICPPTemplateArgument arg, InstantiationContext context) {
if (arg == null)
return null;
if (arg.isNonTypeValue()) {
final ICPPEvaluation eval = arg.getNonTypeEvaluation();
final ICPPEvaluation newEval= eval.instantiate(context, IntegralValue.MAX_RECURSION_DEPTH);
if (eval == newEval)
return arg;
return new CPPTemplateNonTypeArgument(newEval, context.getPoint());
}
final IType orig= arg.getTypeValue();
final IType inst= instantiateType(orig, context);
if (orig == inst)
return arg;
return new CPPTemplateTypeArgument(inst);
}
private static CPPTemplateParameterMap instantiateArgumentMap(ICPPTemplateParameterMap orig,
InstantiationContext context) {
final Integer[] positions = orig.getAllParameterPositions();
CPPTemplateParameterMap newMap= new CPPTemplateParameterMap(positions.length);
for (Integer key : positions) {
ICPPTemplateArgument arg = orig.getArgument(key);
if (arg != null) {
ICPPTemplateArgument newArg = instantiateArgument(arg, context);
if (!isValidArgument(newArg))
newArg = arg;
newMap.put(key, newArg);
} else {
ICPPTemplateArgument[] args = orig.getPackExpansion(key);
if (args != null) {
try {
newMap.put(key, instantiateArguments(args, context, false));
} catch (DOMException e) {
newMap.put(key, args);
}
}
}
}
return newMap;
}
/**
* Instantiates the given type with the provided map and packОffset.
* The context is used to replace templates with their specialization, where appropriate.
*/
public static IType instantiateType(final IType type, InstantiationContext context) {
if (context.getParameterMap() == null)
return type;
TypeInstantiationRequest instantiationRequest = new TypeInstantiationRequest(type, context);
if (!instantiationsInProgress.get().add(instantiationRequest)) {
return type instanceof ICPPFunctionType ?
ProblemFunctionType.RECURSION_IN_LOOKUP : ProblemType.RECURSION_IN_LOOKUP;
}
try {
if (type instanceof ICPPFunctionType) {
final ICPPFunctionType ft = (ICPPFunctionType) type;
IType[] ps = ft.getParameterTypes();
IType[] params = instantiateTypes(ps, context);
final IType r = ft.getReturnType();
IType ret = instantiateType(r, context);
if (ret == r && params == ps) {
return type;
}
// The parameter types need to be adjusted.
for (int i= 0; i < params.length; i++) {
IType p= params[i];
if (!isDependentType(p)) {
params[i]= CPPVisitor.adjustParameterType(p, true);
}
}
return new CPPFunctionType(ret, params, ft.isConst(), ft.isVolatile(),
ft.hasRefQualifier(), ft.isRValueReference(), ft.takesVarArgs());
}
if (type instanceof ICPPTemplateParameter) {
return resolveTemplateTypeParameter((ICPPTemplateParameter) type, context);
}
if (type instanceof ICPPUnknownBinding) {
if (type instanceof TypeOfDependentExpression) {
ICPPEvaluation eval = ((TypeOfDependentExpression) type).getEvaluation();
ICPPEvaluation instantiated = eval.instantiate(context, IntegralValue.MAX_RECURSION_DEPTH);
if (instantiated != eval)
return instantiated.getType(context.getPoint());
} else {
IBinding binding= resolveUnknown((ICPPUnknownBinding) type, context);
if (binding instanceof IType)
return (IType) binding;
return type;
}
}
if (type instanceof TypeOfUnknownMember) {
IBinding binding = resolveUnknown(((TypeOfUnknownMember) type).getUnknownMember(), context);
if (binding instanceof IType) {
return (IType) binding;
} else if (binding instanceof IVariable) {
return ((IVariable) binding).getType();
} else if (binding instanceof IFunction) {
return ((IFunction) binding).getType();
}
return type;
}
if (context.getContextTypeSpecialization() != null && type instanceof IBinding) {
IType unwound= getNestedType(type, TDEF);
ICPPClassSpecialization withinClass = context.getContextClassSpecialization();
if (unwound instanceof ICPPClassType && unwound.isSameType(withinClass.getSpecializedBinding())) {
// Convert (partial) class-templates (specializations) to the more specialized
// version.
if (withinClass instanceof ICPPClassTemplate || !(unwound instanceof ICPPClassTemplate))
return withinClass;
}
IBinding typeAsBinding= (IBinding) type;
IBinding owner= typeAsBinding.getOwner();
if (owner instanceof IType) {
final IType ownerAsType = getNestedType((IType) owner, TDEF);
Object newOwner= owner;
if (ownerAsType instanceof ICPPClassType && ownerAsType.isSameType(withinClass.getSpecializedBinding())) {
// Convert (partial) class-templates (specializations) that are used as
// owner of another binding, to the more specialized version.
newOwner= withinClass;
} else {
newOwner= instantiateType(ownerAsType, context);
}
if (newOwner != owner && newOwner instanceof ICPPClassSpecialization) {
return (IType) ((ICPPClassSpecialization) newOwner).specializeMember(typeAsBinding, context.getPoint());
}
}
if (unwound instanceof ICPPTemplateInstance && !(unwound instanceof ICPPDeferredClassInstance)) {
// Argument of a class specialization can be a nested class subject to specialization.
final ICPPTemplateInstance classInstance = (ICPPTemplateInstance) unwound;
final IBinding origClass = classInstance.getSpecializedBinding();
if (origClass instanceof ICPPClassType) {
ICPPTemplateArgument[] args = classInstance.getTemplateArguments();
ICPPTemplateArgument[] newArgs = instantiateArguments(args, context, false);
if (newArgs != args) {
CPPTemplateParameterMap tparMap =
instantiateArgumentMap(classInstance.getTemplateParameterMap(), context);
return new CPPClassInstance((ICPPClassType) origClass, classInstance.getOwner(), tparMap, args);
}
}
}
}
if (type instanceof ITypeContainer) {
final ITypeContainer typeContainer = (ITypeContainer) type;
IType nestedType = typeContainer.getType();
IType newNestedType = instantiateType(nestedType, context);
if (typeContainer instanceof ICPPPointerToMemberType) {
ICPPPointerToMemberType ptm = (ICPPPointerToMemberType) typeContainer;
IType memberOfClass = ptm.getMemberOfClass();
IType newMemberOfClass = instantiateType(memberOfClass, context);
IType classType = SemanticUtil.getNestedType(newMemberOfClass, CVTYPE | TDEF);
if (!(classType instanceof ICPPClassType || classType instanceof UniqueType
|| classType instanceof ICPPUnknownBinding)) {
return new ProblemType(ISemanticProblem.BINDING_INVALID_TYPE);
}
if (newNestedType != nestedType || newMemberOfClass != memberOfClass) {
return new CPPPointerToMemberType(newNestedType, newMemberOfClass,
ptm.isConst(), ptm.isVolatile(), ptm.isRestrict());
}
return typeContainer;
}
if (typeContainer instanceof IArrayType) {
IArrayType at= (IArrayType) typeContainer;
IValue asize= at.getSize();
if (asize != null) {
IValue newSize= instantiateValue(asize, context, IntegralValue.MAX_RECURSION_DEPTH);
if (newSize != asize) {
return new CPPArrayType(newNestedType, newSize);
}
}
}
if (newNestedType != nestedType) {
return SemanticUtil.replaceNestedType(typeContainer, newNestedType);
}
return typeContainer;
}
if (type instanceof ICPPUnaryTypeTransformation) {
ICPPUnaryTypeTransformation typeTransformation = (ICPPUnaryTypeTransformation) type;
IType operand = instantiateType(typeTransformation.getOperand(), context);
switch (typeTransformation.getOperator()) {
case underlying_type: return TypeTraits.underlyingType(operand);
default: return null; // shouldn't happen
}
}
return type;
} catch (DOMException e) {
return e.getProblem();
} finally {
instantiationsInProgress.get().remove(instantiationRequest);
}
}
/**
* Specialize a template parameter of a nested template by substituting values for the template
* parameters of enclosing templates into the template parameter's default value and, in the case
* of a non-type template parameter, type.
*
* @param owner the specialization of the nested template. This will be the owner of the
* specialized template parameter.
* @param scope the scope of the nested template specialization
* @param specialized the template parameter to be specialized
* @param within the specialization of the enclosing class
* @param point the point of template instantiation
* @return the specialized template parameter
*/
public static ICPPTemplateParameter specializeTemplateParameter(ICPPSpecialization owner, ICPPScope scope,
ICPPTemplateParameter specialized, ICPPClassSpecialization within, IASTNode point) {
if (specialized == null)
return null;
ICPPTemplateParameterMap tpMap = owner.getTemplateParameterMap();
InstantiationContext context = new InstantiationContext(tpMap, 0, within, point);
ICPPTemplateArgument defaultValue = instantiateArgument(specialized.getDefaultValue(), context);
if (specialized instanceof ICPPTemplateNonTypeParameter) {
ICPPTemplateNonTypeParameter spec = (ICPPTemplateNonTypeParameter) specialized;
IType type = instantiateType(spec.getType(), context);
return new CPPTemplateNonTypeParameterSpecialization(owner, scope, spec, defaultValue, type);
} else if (specialized instanceof ICPPTemplateTypeParameter) {
return new CPPTemplateTypeParameterSpecialization(owner, scope,
(ICPPTemplateTypeParameter) specialized, defaultValue);
} else if (specialized instanceof ICPPTemplateTemplateParameter) {
return new CPPTemplateTemplateParameterSpecialization(owner, scope,
(ICPPTemplateTemplateParameter) specialized, defaultValue);
}
return null;
}
/**
* Convenience method for specializing all template parameters in an array.
* See specializeTemplateParameter().
*/
public static ICPPTemplateParameter[] specializeTemplateParameters(ICPPSpecialization owner, ICPPScope scope,
ICPPTemplateParameter[] specialized, ICPPClassSpecialization within, IASTNode point) {
ICPPTemplateParameter[] result = new ICPPTemplateParameter[specialized.length];
for (int i = 0; i < specialized.length; ++i)
result[i] = specializeTemplateParameter(owner, scope, specialized[i], within, point);
return result;
}
public static IBinding instantiateBinding(IBinding binding, InstantiationContext context, int maxDepth)
throws DOMException {
if (binding instanceof ICPPClassTemplate) {
binding = createDeferredInstance((ICPPClassTemplate) binding);
}
if (binding instanceof ICPPUnknownBinding) {
return resolveUnknown((ICPPUnknownBinding) binding, context);
} else if (binding instanceof ICPPMethod
|| binding instanceof ICPPField
|| binding instanceof ICPPEnumeration
|| binding instanceof ICPPClassType) {
IBinding owner = binding.getOwner();
if (!(owner instanceof ICPPSpecialization)) {
owner = instantiateBinding(owner, context, maxDepth);
}
if (owner instanceof ICPPClassSpecialization) {
return ((ICPPClassSpecialization) owner).specializeMember(binding, context.getPoint());
}
} else if (binding instanceof IEnumerator) {
IBinding owner = binding.getOwner();
ICPPTypeSpecialization within = context.getContextTypeSpecialization();
if (within instanceof ICPPEnumerationSpecialization && within.getSpecializedBinding().equals(owner)) {
owner = within;
} else if (!(owner instanceof ICPPSpecialization)) {
owner = instantiateBinding(owner, context, maxDepth);
}
if (owner instanceof ICPPEnumerationSpecialization) {
return ((ICPPEnumerationSpecialization) owner).specializeEnumerator((IEnumerator) binding);
}
} else if (binding instanceof ICPPFunctionInstance) {
// TODO(nathanridge):
// Maybe we should introduce an ICPPDeferredFunctionInstance and have things that can
// return a dependent ICPPFunctionInstance (like instantiateForAddressOfFunction)
// return that when appropriate?
ICPPFunctionInstance origInstance = (ICPPFunctionInstance) binding;
ICPPTemplateArgument[] origArgs = origInstance.getTemplateArguments();
ICPPTemplateArgument[] newArgs = instantiateArguments(origArgs, context, false);
if (origArgs != newArgs) {
CPPTemplateParameterMap newMap =
instantiateArgumentMap(origInstance.getTemplateParameterMap(), context);
IType newType = instantiateType(origInstance.getType(), context);
IType[] newExceptionSpecs = instantiateTypes(origInstance.getExceptionSpecification(), context);
CPPFunctionInstance result = new CPPFunctionInstance((ICPPFunction) origInstance.getTemplateDefinition(),
origInstance.getOwner(), newMap, newArgs, (ICPPFunctionType) newType, newExceptionSpecs);
result.setParameters(specializeParameters(origInstance.getParameters(), result, context, maxDepth));
return result;
}
} else if (binding instanceof ICPPVariableInstance) {
// TODO(nathanridge):
// Similar to the ICPPFunctionInstance case above, perhaps we should have an
// ICPPDeferredVariableInstance.
ICPPVariableInstance origInstance = (ICPPVariableInstance) binding;
ICPPTemplateArgument[] origArgs = origInstance.getTemplateArguments();
ICPPTemplateArgument[] newArgs = instantiateArguments(origArgs, context, false);
if (origArgs != newArgs) {
CPPTemplateParameterMap newMap = instantiateArgumentMap(
origInstance.getTemplateParameterMap(), context);
IType newType = instantiateType(origInstance.getType(), context);
IValue newValue = instantiateValue(origInstance.getInitialValue(), context,
IntegralValue.MAX_RECURSION_DEPTH);
return new CPPVariableInstance(origInstance.getTemplateDefinition(), origInstance.getOwner(),
newMap, newArgs, newType, newValue);
}
}
return binding;
}
public static IType resolveTemplateTypeParameter(final ICPPTemplateParameter tpar,
InstantiationContext context) {
ICPPTemplateArgument arg= null;
if (tpar.isParameterPack()) {
if (context.hasPackOffset()) {
ICPPTemplateArgument[] args = context.getPackExpansion(tpar);
if (args != null) {
if (context.getPackOffset() >= args.length) {
return new ProblemBinding(context.getPoint(), IProblemBinding.SEMANTIC_INVALID_TYPE,
tpar.getNameCharArray());
}
arg= args[context.getPackOffset()];
}
if (context.shouldExpandPack()) {
if (arg != null) {
IType type = arg.getTypeValue();
if (type instanceof ICPPParameterPackType) {
arg = new CPPTemplateTypeArgument(((ICPPParameterPackType) type).getType());
context.setPackExpanded(true);
}
}
}
}
} else {
arg= context.getArgument(tpar);
}
if (arg != null) {
IType t= arg.getOriginalTypeValue();
if (t != null)
return t;
}
return (IType) tpar;
}
/**
* Checks whether a given name corresponds to a template declaration and returns the AST node
* for it. This works for the name of a template-definition and also for a name needed to
* qualify a member definition:
* <pre>
* template &lt;typename T&gt; void MyTemplate&ltT&gt;::member() {}
* </pre>
* @param name a name for which the corresponding template declaration is searched for.
* @return the template declaration or {@code null} if {@code name} does not correspond
* to a template declaration.
*/
public static ICPPASTTemplateDeclaration getTemplateDeclaration(IASTName name) {
if (name == null)
return null;
// first look for a related sequence of template declarations
ICPPASTInternalTemplateDeclaration tdecl= getInnerTemplateDeclaration(name);
if (tdecl == null)
return null;
name= name.getLastName();
IASTNode parent= name.getParent();
if (!(parent instanceof ICPPASTQualifiedName)) {
if (parent instanceof ICPPASTTemplateId) {
return null;
}
// One name: use innermost template declaration
return tdecl;
}
// last name can be associated even if it is not a template-id
final ICPPASTQualifiedName qname= (ICPPASTQualifiedName) parent;
final IASTName lastName = qname.getLastName();
final boolean lastIsTemplate= tdecl.isAssociatedWithLastName();
if (name == lastName) {
if (lastIsTemplate) {
return tdecl;
}
return null;
}
// Not the last name, search for the matching template declaration
if (!(name instanceof ICPPASTTemplateId))
return null;
if (lastIsTemplate) {
// skip one
tdecl= getDirectlyEnclosingTemplateDeclaration(tdecl);
}
final ICPPASTNameSpecifier[] qualifier= qname.getQualifier();
for (int i = qualifier.length - 1; tdecl != null && i >= 0; i--) {
final ICPPASTNameSpecifier n = qualifier[i];
if (n == name) {
return tdecl;
}
if (n instanceof ICPPASTTemplateId) {
tdecl= getDirectlyEnclosingTemplateDeclaration(tdecl);
}
}
// not enough template declarations
return null;
}
public static void associateTemplateDeclarations(ICPPASTInternalTemplateDeclaration tdecl) {
// Find innermost template declaration
IASTDeclaration decl= tdecl.getDeclaration();
while (decl instanceof ICPPASTInternalTemplateDeclaration) {
tdecl= (ICPPASTInternalTemplateDeclaration) decl;
decl= tdecl.getDeclaration();
}
final ICPPASTInternalTemplateDeclaration innerMostTDecl= tdecl;
// Find name declared within the template declaration
final IASTName declName= getNameForDeclarationInTemplateDeclaration(decl);
// Count non-empty template declarations
int instDeclCount= 0;
int tdeclCount= 0;
IASTNode node= tdecl;
while (node instanceof ICPPASTInternalTemplateDeclaration) {
tdecl = (ICPPASTInternalTemplateDeclaration) node;
node= node.getParent();
if (tdecl.getTemplateParameters().length == 0) {
instDeclCount++;
} else {
instDeclCount= 0;
}
tdeclCount++;
}
final ICPPASTInternalTemplateDeclaration outerMostTDecl= tdecl;
final int paramTDeclCount = tdeclCount-instDeclCount;
// Determine association of names with template declarations
boolean lastIsTemplate= true;
int nestingLevel;
if (declName instanceof ICPPASTQualifiedName) {
ICPPASTQualifiedName qname= (ICPPASTQualifiedName) declName;
// Count dependent-ids
CharArraySet tparnames= collectTemplateParameterNames(outerMostTDecl);
int depIDCount= 0;
IBinding owner= null;
final ICPPASTNameSpecifier[] qualifier= qname.getQualifier();
for (int i = 0; i < qualifier.length; i++) {
ICPPASTNameSpecifier n= qualifier[i];
if (n instanceof ICPPASTTemplateId) {
if (depIDCount > 0 || usesTemplateParameter((ICPPASTTemplateId) n, tparnames)) {
depIDCount++;
}
}
if (depIDCount == 0) {
owner= n.resolveBinding();
}
}
if (qname.getLastName() instanceof ICPPASTTemplateId
|| paramTDeclCount > depIDCount // not enough template ids
|| qualifier.length < 1 // ::name
) {
lastIsTemplate= true;
depIDCount++;
} else {
lastIsTemplate= false;
}
nestingLevel= 0;
if (owner != null) {
int consumesTDecl= 0;
IBinding b= owner;
if (b instanceof IType) {
IType t= SemanticUtil.getNestedType((IType) b, TDEF);
if (t instanceof IBinding)
b= (IBinding) t;
}
while (b != null) {
if (b instanceof ICPPTemplateInstance) {
nestingLevel++;
if (!((ICPPTemplateInstance) b).isExplicitSpecialization())
consumesTDecl++;
} else if (b instanceof ICPPClassTemplate || b instanceof ICPPClassTemplatePartialSpecialization) {
nestingLevel++;
consumesTDecl++;
}
b= b.getOwner();
}
if (depIDCount > 0) {
nestingLevel+= depIDCount;
} else if (consumesTDecl < tdeclCount && !lastIsTemplate) {
nestingLevel++;
lastIsTemplate= true;
}
} else {
nestingLevel+= depIDCount;
node= outerMostTDecl.getParent();
while (node != null) {
if (node instanceof ICPPASTInternalTemplateDeclaration) {
nestingLevel+= ((ICPPASTInternalTemplateDeclaration) node).getNestingLevel() + 1;
break;
}
node= node.getParent();
}
}
} else {
nestingLevel= 1;
lastIsTemplate= true;
if (!isFriendFunctionDeclaration(innerMostTDecl.getDeclaration())) {
node= outerMostTDecl.getParent();
while (node != null) {
if (node instanceof ICPPASTInternalTemplateDeclaration) {
nestingLevel+= ((ICPPASTInternalTemplateDeclaration) node).getNestingLevel() + 1;
break;
}
node= node.getParent();
}
}
}
node= innerMostTDecl;
while (node instanceof ICPPASTInternalTemplateDeclaration) {
if (--nestingLevel < 0)
nestingLevel= 0;
tdecl= (ICPPASTInternalTemplateDeclaration) node;
tdecl.setNestingLevel((short) nestingLevel);
tdecl.setAssociatedWithLastName(false);
node= tdecl.getParent();
}
innerMostTDecl.setAssociatedWithLastName(lastIsTemplate);
}
private static boolean isFriendFunctionDeclaration(IASTDeclaration declaration) {
while (declaration instanceof ICPPASTTemplateDeclaration) {
declaration= ((ICPPASTTemplateDeclaration) declaration).getDeclaration();
}
if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration sdecl = (IASTSimpleDeclaration) declaration;
ICPPASTDeclSpecifier declspec= (ICPPASTDeclSpecifier) sdecl.getDeclSpecifier();
if (declspec.isFriend()) {
IASTDeclarator[] dtors= sdecl.getDeclarators();
if (dtors.length == 1 && ASTQueries.findTypeRelevantDeclarator(dtors[0]) instanceof IASTFunctionDeclarator) {
return true;
}
}
}
return false;
}
private static CharArraySet collectTemplateParameterNames(ICPPASTTemplateDeclaration tdecl) {
CharArraySet set= new CharArraySet(4);
while (true) {
ICPPASTTemplateParameter[] pars = tdecl.getTemplateParameters();
for (ICPPASTTemplateParameter par : pars) {
IASTName name= getTemplateParameterName(par);
if (name != null)
set.put(name.getLookupKey());
}
final IASTNode next= tdecl.getDeclaration();
if (next instanceof ICPPASTTemplateDeclaration) {
tdecl= (ICPPASTTemplateDeclaration) next;
} else {
break;
}
}
return set;
}
private static boolean usesTemplateParameter(final ICPPASTTemplateId id, final CharArraySet names) {
final boolean[] result= {false};
ASTVisitor v= new ASTVisitor(false) {
{ shouldVisitNames= true; shouldVisitAmbiguousNodes=true;}
@Override
public int visit(IASTName name) {
if (name instanceof ICPPASTTemplateId)
return PROCESS_CONTINUE;
if (name instanceof ICPPASTQualifiedName) {
ICPPASTQualifiedName qname= (ICPPASTQualifiedName) name;
if (qname.isFullyQualified())
return PROCESS_SKIP;
return PROCESS_CONTINUE;
}
if (names.containsKey(name.getLookupKey())) {
IASTNode parent= name.getParent();
if (parent instanceof ICPPASTQualifiedName) {
ICPPASTNameSpecifier[] qualifier = ((ICPPASTQualifiedName) parent).getQualifier();
if (qualifier.length > 0 && qualifier[0] != name) {
return PROCESS_CONTINUE;
}
result[0]= true;
return PROCESS_ABORT;
} else if (parent instanceof IASTIdExpression ||
parent instanceof ICPPASTNamedTypeSpecifier) {
result[0]= true;
return PROCESS_ABORT;
}
}
return PROCESS_CONTINUE;
}
@Override
public int visit(ASTAmbiguousNode node) {
IASTNode[] alternatives= node.getNodes();
for (IASTNode alt : alternatives) {
if (!alt.accept(this))
return PROCESS_ABORT;
}
return PROCESS_CONTINUE;
}
};
id.accept(v);
return result[0];
}
private static IASTName getNameForDeclarationInTemplateDeclaration(IASTDeclaration decl) {
IASTName name= null;
if (decl instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration sdecl= (IASTSimpleDeclaration) decl;
IASTDeclarator[] dtors = sdecl.getDeclarators();
if (dtors != null && dtors.length > 0) {
name= ASTQueries.findInnermostDeclarator(dtors[0]).getName();
} else {
IASTDeclSpecifier declspec = sdecl.getDeclSpecifier();
if (declspec instanceof IASTCompositeTypeSpecifier) {
name= ((IASTCompositeTypeSpecifier) declspec).getName();
} else if (declspec instanceof IASTElaboratedTypeSpecifier) {
name= ((IASTElaboratedTypeSpecifier) declspec).getName();
}
}
} else if (decl instanceof IASTFunctionDefinition) {
IASTFunctionDefinition fdef= (IASTFunctionDefinition) decl;
name= ASTQueries.findInnermostDeclarator(fdef.getDeclarator()).getName();
}
return name;
}
private static ICPPASTInternalTemplateDeclaration getInnerTemplateDeclaration(final IASTName name) {
IASTNode parent = name.getParent();
while (parent instanceof IASTName) {
parent = parent.getParent();
}
if (parent instanceof IASTDeclSpecifier) {
if (!(parent instanceof IASTCompositeTypeSpecifier) &&
!(parent instanceof IASTElaboratedTypeSpecifier)) {
return null;
}
parent = parent.getParent();
} else {
while (parent instanceof IASTDeclarator) {
parent = parent.getParent();
}
}
if (!(parent instanceof IASTDeclaration))
return null;
parent = parent.getParent();
if (parent instanceof ICPPASTInternalTemplateDeclaration)
return (ICPPASTInternalTemplateDeclaration) parent;
return null;
}
private static ICPPASTInternalTemplateDeclaration getDirectlyEnclosingTemplateDeclaration(
ICPPASTInternalTemplateDeclaration tdecl) {
final IASTNode parent= tdecl.getParent();
if (parent instanceof ICPPASTInternalTemplateDeclaration)
return (ICPPASTInternalTemplateDeclaration) parent;
return null;
}
public static IASTName getTemplateName(ICPPASTTemplateDeclaration templateDecl) {
if (templateDecl == null) return null;
ICPPASTTemplateDeclaration decl = templateDecl;
while (decl.getParent() instanceof ICPPASTTemplateDeclaration)
decl = (ICPPASTTemplateDeclaration) decl.getParent();
IASTDeclaration nestedDecl = templateDecl.getDeclaration();
while (nestedDecl instanceof ICPPASTTemplateDeclaration) {
nestedDecl = ((ICPPASTTemplateDeclaration) nestedDecl).getDeclaration();
}
IASTName name = null;
if (nestedDecl instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simple = (IASTSimpleDeclaration) nestedDecl;
if (simple.getDeclarators().length == 1) {
IASTDeclarator dtor = simple.getDeclarators()[0];
while (dtor.getNestedDeclarator() != null)
dtor = dtor.getNestedDeclarator();
name = dtor.getName();
} else if (simple.getDeclarators().length == 0) {
IASTDeclSpecifier spec = simple.getDeclSpecifier();
if (spec instanceof ICPPASTCompositeTypeSpecifier) {
name = ((ICPPASTCompositeTypeSpecifier) spec).getName();
} else if (spec instanceof ICPPASTElaboratedTypeSpecifier) {
name = ((ICPPASTElaboratedTypeSpecifier) spec).getName();
}
}
} else if (nestedDecl instanceof IASTFunctionDefinition) {
IASTDeclarator declarator = ((IASTFunctionDefinition) nestedDecl).getDeclarator();
declarator= ASTQueries.findInnermostDeclarator(declarator);
name = declarator.getName();
}
if (name != null) {
if (name instanceof ICPPASTQualifiedName) {
ICPPASTNameSpecifier[] qualifier = ((ICPPASTQualifiedName) name).getQualifier();
IASTDeclaration currDecl = decl;
for (ICPPASTNameSpecifier segment : qualifier) {
if (segment instanceof ICPPASTTemplateId) {
if (currDecl == templateDecl) {
return (IASTName) segment;
}
if (!(currDecl instanceof ICPPASTTemplateDeclaration)) {
return null;
}
currDecl = ((ICPPASTTemplateDeclaration) currDecl).getDeclaration();
}
}
if (currDecl == templateDecl) {
return name.getLastName();
}
} else {
return name;
}
}
return null;
}
public static boolean areSameArguments(ICPPTemplateArgument[] args, ICPPTemplateArgument[] specArgs) {
if (args.length != specArgs.length) {
return false;
}
for (int i= 0; i < args.length; i++) {
if (!specArgs[i].isSameValue(args[i]))
return false;
}
return true;
}
/**
* @param id the template id containing the template arguments
* @return an array of template arguments, currently modeled as IType objects.
* The empty ICPPTemplateArgument array is returned if id is {@code null}
*/
public static ICPPTemplateArgument[] createTemplateArgumentArray(ICPPASTTemplateId id) throws DOMException {
ICPPTemplateArgument[] result= ICPPTemplateArgument.EMPTY_ARGUMENTS;
if (id != null) {
IASTNode[] args= id.getTemplateArguments();
result = new ICPPTemplateArgument[args.length];
for (int i = 0; i < args.length; i++) {
IASTNode arg= args[i];
if (arg instanceof IASTTypeId) {
result[i]= new CPPTemplateTypeArgument(CPPVisitor.createType((IASTTypeId) arg));
} else if (arg instanceof ICPPASTExpression) {
ICPPASTExpression expr= (ICPPASTExpression) arg;
result[i]= new CPPTemplateNonTypeArgument(expr.getEvaluation(), expr);
} else if (arg instanceof ICPPASTAmbiguousTemplateArgument) {
IProblemBinding problem = new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS);
throw new DOMException(problem);
} else {
throw new IllegalArgumentException("Unexpected type: " + arg.getClass().getName()); //$NON-NLS-1$
}
}
}
return result;
}
static ICPPFunction[] instantiateForFunctionCall(ICPPFunction[] fns, ICPPTemplateArgument[] tmplArgs,
List<IType> fnArgs, List<ValueCategory> argCats, boolean withImpliedObjectArg, IASTNode point) {
// Extract template arguments.
boolean requireTemplate= tmplArgs != null;
boolean haveTemplate= false;
for (final ICPPFunction func : fns) {
if (func instanceof ICPPConstructor || (func instanceof ICPPMethod && ((ICPPMethod) func).isDestructor()))
requireTemplate= false;
if (func instanceof ICPPFunctionTemplate) {
if (containsDependentType(fnArgs))
return new ICPPFunction[] {CPPDeferredFunction.createForCandidates(fns)};
if (requireTemplate && hasDependentArgument(tmplArgs))
return new ICPPFunction[] {CPPDeferredFunction.createForCandidates(fns)};
haveTemplate= true;
break;
}
}
if (!haveTemplate && !requireTemplate)
return fns;
final List<ICPPFunction> result= new ArrayList<>(fns.length);
for (ICPPFunction fn : fns) {
if (fn != null) {
if (fn instanceof ICPPFunctionTemplate) {
ICPPFunctionTemplate fnTmpl= (ICPPFunctionTemplate) fn;
ICPPFunction inst = instantiateForFunctionCall(fnTmpl, tmplArgs, fnArgs, argCats,
withImpliedObjectArg, point);
if (inst != null)
result.add(inst);
} else if (!requireTemplate || fn instanceof ICPPUnknownBinding) {
result.add(fn);
}
}
}
return result.toArray(new ICPPFunction[result.size()]);
}
private static ICPPFunction instantiateForFunctionCall(ICPPFunctionTemplate template,
ICPPTemplateArgument[] tmplArgs, List<IType> fnArgs, List<ValueCategory> argCats,
boolean withImpliedObjectArg, IASTNode point) {
if (withImpliedObjectArg && template instanceof ICPPMethod) {
fnArgs= fnArgs.subList(1, fnArgs.size());
argCats= argCats.subList(1, argCats.size());
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.size());
try {
ICPPTemplateArgument[] args=
TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, argCats, map, point);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map, point);
if (instance instanceof ICPPFunction) {
final ICPPFunction f = (ICPPFunction) instance;
if (isValidFunctionType(f.getType())) {
// The number of arguments have been checked against the function
// template's required argument count at an earlier stage. However,
// the process of instantiation can increase the required argument
// count by expanding parameter packs. If arguments are provided
// for a parameter pack explicitly, it's possible for deduction to
// succeed without having enough function arguments to match a
// corresponding function parameter pack - so we check again.
if (fnArgs.size() >= f.getRequiredArgumentCount())
return f;
}
}
}
} catch (DOMException e) {
}
return null;
}
/**
* Checks if the given function type is problem-free and that the return type is not a function set.
*/
public static boolean isValidFunctionType(IFunctionType type) {
if (!SemanticUtil.isValidType(type))
return false;
IType t = type.getReturnType();
t = SemanticUtil.getNestedType(t, ALLCVQ | TDEF | REF);
if (t instanceof IPointerType)
t = ((IPointerType) t).getType();
if (t instanceof FunctionSetType)
return false;
return true;
}
/**
* 14.8.2.3 Deducing conversion function template arguments
* @param point
*/
static ICPPFunction[] instantiateConversionTemplates(ICPPFunction[] functions, IType conversionType,
IASTNode point) {
boolean checkedForDependentType= false;
ICPPFunction[] result= functions;
int i= 0;
boolean done= false;
for (ICPPFunction f : functions) {
ICPPFunction inst = f;
if (f instanceof ICPPFunctionTemplate) {
ICPPFunctionTemplate template= (ICPPFunctionTemplate) f;
inst= null;
// Extract template arguments and parameter types.
if (!checkedForDependentType) {
if (isDependentType(conversionType)) {
inst= CPPDeferredFunction.createForCandidates(functions);
done= true;
}
checkedForDependentType= true;
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(1);
try {
ICPPTemplateArgument[] args=
TemplateArgumentDeduction.deduceForConversion(template, conversionType, map, point);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map, point);
if (instance instanceof ICPPFunction) {
inst= (ICPPFunction) instance;
}
}
} catch (DOMException e) {
// try next candidate
}
}
if (result != functions || f != inst) {
if (result == functions) {
result= new ICPPFunction[functions.length];
System.arraycopy(functions, 0, result, 0, i);
}
result[i++]= inst;
}
if (done)
break;
}
return result;
}
/**
* 14.8.2.6 Deducing template arguments from a function declaration
* @param point
* @return
*/
static ICPPFunction instantiateForFunctionDeclaration(ICPPFunctionTemplate template,
ICPPTemplateArgument[] args, ICPPFunctionType functionType, IASTNode point) {
CPPTemplateParameterMap map= new CPPTemplateParameterMap(1);
try {
args= TemplateArgumentDeduction.deduceForDeclaration(template, args, functionType, map, point);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map, point);
if (instance instanceof ICPPFunction) {
return (ICPPFunction) instance;
}
}
} catch (DOMException e) {
// try next candidate
}
return null;
}
/**
* 14.8.2.2 Deducing template arguments taking the address of a function template [temp.deduct.funcaddr]
*/
static ICPPFunction instantiateForAddressOfFunction(ICPPFunctionTemplate template, IFunctionType target,
ICPPTemplateArgument[] args, IASTNode point) {
try {
if (target != null && isDependentType(target)) {
return CPPDeferredFunction.createForCandidates(template);
}
if (template instanceof ICPPConstructor || args == null)
args= ICPPTemplateArgument.EMPTY_ARGUMENTS;
CPPTemplateParameterMap map= new CPPTemplateParameterMap(4);
args= TemplateArgumentDeduction.deduceForAddressOf(template, args, target, map, point);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map, point);
if (instance instanceof ICPPFunction) {
return (ICPPFunction) instance;
}
}
} catch (DOMException e) {
}
return null;
}
// 14.5.6.2 Partial ordering of function templates
static int orderFunctionTemplates(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2, TypeSelection mode, IASTNode point)
throws DOMException {
if (f1 == f2)
return 0;
if (f1 == null)
return -1;
if (f2 == null)
return 1;
int s1 = compareSpecialization(f1, f2, mode, point);
int s2 = compareSpecialization(f2, f1, mode, point);
if (s1 == s2)
return 0;
if (s1 < 0 || s2 > 0)
return -1;
assert s2 < 0 || s1 > 0;
return 1;
}
private static ICPPFunction transferFunctionTemplate(ICPPFunctionTemplate f, IASTNode point) throws DOMException {
final ICPPTemplateParameter[] tpars = f.getTemplateParameters();
final int argLen = tpars.length;
// Create arguments and map
ICPPTemplateArgument[] args = new ICPPTemplateArgument[argLen];
CPPTemplateParameterMap map = new CPPTemplateParameterMap(argLen);
for (int i = 0; i < argLen; i++) {
final ICPPTemplateParameter tpar = tpars[i];
final ICPPTemplateArgument arg = uniqueArg(tpar);
args[i]= arg;
if (tpar.isParameterPack()) {
map.put(tpar, new ICPPTemplateArgument[] {arg});
} else {
map.put(tpar, arg);
}
}
IBinding result = instantiateFunctionTemplate(f, args, map, point);
if (result instanceof ICPPFunction)
return (ICPPFunction) result;
return null;
}
private static ICPPTemplateArgument uniqueArg(final ICPPTemplateParameter tpar) throws DOMException {
final ICPPTemplateArgument arg;
if (tpar instanceof ICPPTemplateNonTypeParameter) {
arg = new CPPTemplateNonTypeArgument(IntegralValue.unique(), ((ICPPTemplateNonTypeParameter) tpar).getType());
} else {
arg = new CPPTemplateTypeArgument(new UniqueType(tpar.isParameterPack()));
}
return arg;
}
private static ICPPFunctionType getFunctionTypeIgnoringParametersWithDefaults(ICPPFunction function) {
ICPPParameter[] parameters = function.getParameters();
IType[] parameterTypes = new IType[parameters.length];
int i;
for (i = 0; i < parameters.length; ++i) {
ICPPParameter parameter = parameters[i];
if (!parameter.hasDefaultValue()) {
parameterTypes[i] = parameter.getType();
} else {
break;
}
}
ICPPFunctionType originalType = function.getType();
if (i == parameters.length) // No parameters with default arguments.
return originalType;
return new CPPFunctionType(originalType.getReturnType(), ArrayUtil.trim(parameterTypes),
originalType.isConst(), originalType.isVolatile(), originalType.hasRefQualifier(),
originalType.isRValueReference(), originalType.takesVarArgs());
}
private static int compareSpecialization(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2, TypeSelection mode, IASTNode point) throws DOMException {
ICPPFunction transF1 = transferFunctionTemplate(f1, point);
if (transF1 == null)
return -1;
final ICPPFunctionType ft2 = f2.getType();
// Ignore parameters with default arguments in the transformed function template
// as per [temp.func.order] p5.
final ICPPFunctionType transFt1 = getFunctionTypeIgnoringParametersWithDefaults(transF1);
IType[] pars;
IType[] args;
switch (mode) {
case RETURN_TYPE:
pars= new IType[] {ft2.getReturnType()};
args= new IType[] {transFt1.getReturnType()};
break;
case PARAMETERS_AND_RETURN_TYPE:
pars= SemanticUtil.concatTypes(ft2.getReturnType(), ft2.getParameterTypes());
args= SemanticUtil.concatTypes(transFt1.getReturnType(), transFt1.getParameterTypes());
break;
case PARAMETERS:
default:
pars= ft2.getParameterTypes();
args = transFt1.getParameterTypes();
boolean nonStaticMember1= isNonStaticMember(f1);
boolean nonStaticMember2= isNonStaticMember(f2);
if (nonStaticMember1 != nonStaticMember2) {
if (nonStaticMember1) {
args= SemanticUtil.addImplicitParameterType(args, (ICPPMethod) f1);
} else {
pars= SemanticUtil.addImplicitParameterType(pars, (ICPPMethod) f2);
}
}
break;
}
return TemplateArgumentDeduction.deduceForPartialOrdering(f2.getTemplateParameters(), pars, args, point);
}
private static boolean isNonStaticMember(ICPPFunctionTemplate f) {
return (f instanceof ICPPMethod) && !((ICPPMethod) f).isStatic();
}
private static ICPPPartialSpecialization findPartialSpecialization(ICPPPartiallySpecializable template,
ICPPTemplateArgument[] args) throws DOMException {
ICPPPartialSpecialization[] pspecs = template.getPartialSpecializations();
if (pspecs != null && pspecs.length > 0) {
final String argStr= ASTTypeUtil.getArgumentListString(args, true);
for (ICPPPartialSpecialization pspec : pspecs) {
if (argStr.equals(ASTTypeUtil.getArgumentListString(pspec.getTemplateArguments(), true)))
return pspec;
}
}
return null;
}
private static IBinding selectSpecialization(ICPPPartiallySpecializable template, ICPPTemplateArgument[] args,
boolean isDef, IASTNode point) throws DOMException {
if (template == null) {
return null;
}
ICPPPartialSpecialization[] specializations = template.getPartialSpecializations();
if (specializations == null || specializations.length == 0) {
return null;
}
ICPPPartialSpecialization bestMatch = null;
CPPTemplateParameterMap bestMap= null;
boolean bestMatchIsBest = true;
for (ICPPPartialSpecialization specialization : specializations) {
final CPPTemplateParameterMap map = new CPPTemplateParameterMap(args.length);
ICPPTemplateArgument[] specializationArguments = specialization.getTemplateArguments();
if (TemplateArgumentDeduction.fromTemplateArguments(
specialization.getTemplateParameters(), specializationArguments, args, map, point) &&
checkInstantiationOfArguments(specializationArguments, map, point)) {
int compare = orderSpecializations(bestMatch, specialization, point);
if (compare == 0) {
bestMatchIsBest = false;
} else if (compare < 0) {
bestMatch = specialization;
bestMap= map;
bestMatchIsBest = true;
}
}
}
// 14.5.4.1 If none of the specializations is more specialized than all the other matching
// specializations, then the use of the class template is ambiguous and the program is
// ill-formed.
if (!bestMatchIsBest) {
return new CPPTemplateDefinition.CPPTemplateProblem(point,
IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, template.getNameCharArray());
}
if (bestMatch == null)
return null;
if (bestMatch instanceof ICPPClassTemplatePartialSpecialization) {
bestMatch = SemanticUtil.mapToAST((ICPPClassTemplatePartialSpecialization) bestMatch, point);
}
return instantiatePartialSpecialization(bestMatch, args, isDef, bestMap, point);
}
private static boolean checkInstantiationOfArguments(ICPPTemplateArgument[] args,
CPPTemplateParameterMap tpMap, IASTNode point) throws DOMException {
return instantiateArguments(args, new InstantiationContext(tpMap, point), true) != null;
}
/**
* Compare spec1 to spec2. Return > 0 if spec1 is more specialized, < 0 if spec2
* is more specialized, = 0 otherwise.
* @param spec1
* @param spec2
* @param point
* @return
* @throws DOMException
*/
static private int orderSpecializations(ICPPPartialSpecialization spec1, ICPPPartialSpecialization spec2, IASTNode point) throws DOMException {
if (spec1 == null) {
return -1;
}
// we avoid the transformation to function templates, of which the one parameter
// will be used in the end.
// 14.5.5.2
// A template is more specialized than another if and only if it is at least as specialized as the
// other template and that template is not at least as specialized as the first.
boolean f1IsAtLeastAsSpecializedAsF2 = isAtLeastAsSpecializedAs(spec1, spec2, point);
boolean f2IsAtLeastAsSpecializedAsF1 = isAtLeastAsSpecializedAs(spec2, spec1, point);
if (f1IsAtLeastAsSpecializedAsF2 == f2IsAtLeastAsSpecializedAsF1)
return 0;
if (f1IsAtLeastAsSpecializedAsF2)
return 1;
return -1;
}
private static boolean isAtLeastAsSpecializedAs(ICPPPartialSpecialization f1, ICPPPartialSpecialization f2, IASTNode point) throws DOMException {
// 14.5.5.2
// Using the transformed parameter list, perform argument deduction against the other
// function template
// The transformed template is at least as specialized as the other if and only if the deduction
// succeeds and the deduced parameter types are an exact match.
final ICPPTemplateParameter[] tpars1 = f1.getTemplateParameters();
final ICPPTemplateParameter[] tpars2 = f2.getTemplateParameters();
final ICPPTemplateArgument[] targs1 = f1.getTemplateArguments();
final ICPPTemplateArgument[] targs2 = f2.getTemplateArguments();
// Transfer arguments of specialization 1
final int tpars1Len = tpars1.length;
ICPPTemplateArgument[] args = new ICPPTemplateArgument[tpars1Len];
final CPPTemplateParameterMap transferMap= new CPPTemplateParameterMap(tpars1Len);
for (int i = 0; i < tpars1Len; i++) {
final ICPPTemplateParameter param = tpars1[i];
final ICPPTemplateArgument arg = uniqueArg(param);
args[i]= arg;
if (param.isParameterPack()) {
transferMap.put(param, new ICPPTemplateArgument[] { arg });
} else {
transferMap.put(param, arg);
}
}
final ICPPTemplateArgument[] transferredArgs1 =
instantiateArguments(targs1, new InstantiationContext(transferMap, point), false);
// Deduce arguments for specialization 2
final CPPTemplateParameterMap deductionMap= new CPPTemplateParameterMap(2);
return TemplateArgumentDeduction.fromTemplateArguments(tpars2, targs2, transferredArgs1, deductionMap, point);
}
static boolean isValidArgument(ICPPTemplateArgument arg) {
return arg != null && SemanticUtil.isValidType(arg.isTypeValue() ? arg.getTypeValue() : arg.getTypeOfNonTypeValue());
}
static ICPPTemplateArgument matchTemplateParameterAndArgument(ICPPTemplateDefinition template,
ICPPTemplateParameter param, ICPPTemplateArgument arg, CPPTemplateParameterMap map, IASTNode point) {
if (!isValidArgument(arg)) {
return null;
}
if (param instanceof ICPPTemplateTypeParameter) {
IType t= arg.getTypeValue();
if (t != null && ! (t instanceof ICPPTemplateDefinition))
return arg;
return null;
}
if (param instanceof ICPPTemplateTemplateParameter) {
IType t= arg.getTypeValue();
while (!(t instanceof ICPPTemplateDefinition)) {
if (t instanceof ICPPClassSpecialization) {
// Undo the effect of specializing a template when the unqualified name
// is used within the template itself.
t= ((ICPPClassSpecialization) t).getSpecializedBinding();
} else {
return null;
}
}
ICPPTemplateParameter[] pParams = null;
ICPPTemplateParameter[] aParams = null;
try {
pParams = ((ICPPTemplateTemplateParameter) param).getTemplateParameters();
aParams = ((ICPPTemplateDefinition) t).getTemplateParameters();
if (!matchTemplateTemplateParameters(pParams, aParams))
return null;
} catch (DOMException e) {
return null;
}
return arg;
}
if (param instanceof ICPPTemplateNonTypeParameter) {
if (!arg.isNonTypeValue())
return null;
IType argType= arg.getTypeOfNonTypeValue();
try {
IType pType = ((ICPPTemplateNonTypeParameter) param).getType();
if (pType instanceof ICPPParameterPackType) {
pType= ((ICPPParameterPackType) pType).getType();
}
if (map != null && pType != null) {
pType= instantiateType(pType, new InstantiationContext(map, point));
}
if (argType instanceof ICPPParameterPackType) {
argType = ((ICPPParameterPackType) argType).getType();
}
if (argType instanceof ICPPUnknownType) {
return new CPPTemplateNonTypeArgument(arg.getNonTypeValue(), pType);
}
return convertNonTypeTemplateArgument(template, pType, arg, point);
} catch (DOMException e) {
return null;
}
}
assert false;
return null;
}
private static boolean matchTemplateTemplateParameters(ICPPTemplateParameter[] pParams,
ICPPTemplateParameter[] aParams) throws DOMException {
int pi= 0;
int ai= 0;
while (pi < pParams.length && ai < aParams.length) {
final ICPPTemplateParameter pp = pParams[pi];
final ICPPTemplateParameter ap = aParams[ai];
// A parameter pack does not match a regular template parameter.
if (ap.isParameterPack() && !pp.isParameterPack())
return false;
boolean pb= pp instanceof ICPPTemplateTypeParameter;
boolean ab= ap instanceof ICPPTemplateTypeParameter;
if (pb != ab)
return false;
if (pb) {
// Both are template type parameters
} else {
pb= pp instanceof ICPPTemplateNonTypeParameter;
ab= ap instanceof ICPPTemplateNonTypeParameter;
if (pb != ab)
return false;
if (pb) {
// Both are non-type parameters
} else {
if (!(pp instanceof ICPPTemplateTemplateParameter) ||
!(ap instanceof ICPPTemplateTemplateParameter)) {
assert false;
return false;
}
if (!matchTemplateTemplateParameters(((ICPPTemplateTemplateParameter) pp).getTemplateParameters(),
((ICPPTemplateTemplateParameter) ap).getTemplateParameters()))
return false;
}
}
if (!pp.isParameterPack())
pi++;
ai++;
}
if (pi < pParams.length) {
if (pi == pParams.length - 1 && pParams[pi].isParameterPack())
return true;
return false;
}
return ai == aParams.length;
}
/**
* Converts the template argument {@code arg} to match the parameter type {@code paramType}
* or returns {@code null}, if this violates the rules specified in 14.3.2 - 5.
*
* @throws DOMException
*/
private static ICPPTemplateArgument convertNonTypeTemplateArgument(ICPPTemplateDefinition template,
final IType paramType, ICPPTemplateArgument arg, IASTNode point) throws DOMException {
// 14.1s8 function to pointer and array to pointer conversions.
IType a= arg.getTypeOfNonTypeValue();
IType p;
if (paramType instanceof IFunctionType) {
p = new CPPPointerType(paramType);
} else if (paramType instanceof IArrayType) {
p = new CPPPointerType(((IArrayType) paramType).getType());
} else {
p= paramType;
if (p != null && p.isSameType(a))
return arg;
}
if (a instanceof FunctionSetType) {
if (p instanceof IPointerType) {
p= ((IPointerType) p).getType();
}
if (p instanceof IFunctionType) {
final CPPFunctionSet functionSet = ((FunctionSetType) a).getFunctionSet();
for (ICPPFunction f : functionSet.getBindings()) {
if (p.isSameType(f.getType())) {
functionSet.applySelectedFunction(f);
return new CPPTemplateNonTypeArgument(new EvalBinding(f, null, template), point);
}
}
}
return null;
}
Cost cost = Conversions.checkImplicitConversionSequence(p, a, LVALUE, UDCMode.FORBIDDEN,
Context.ORDINARY, point);
if (cost == null || !cost.converts()) {
ICPPEvaluation eval = arg.getNonTypeEvaluation();
ICPPEvaluation newEval = CPPEvaluation.maybeApplyConversion(eval, p, point, false);
if (newEval == EvalFixed.INCOMPLETE && newEval != eval)
return null;
return new CPPTemplateNonTypeArgument(newEval, point);
}
return new CPPTemplateNonTypeArgument(arg.getNonTypeValue(), paramType);
}
static boolean argsAreTrivial(ICPPTemplateParameter[] pars, ICPPTemplateArgument[] args) {
if (pars.length != args.length) {
return false;
}
for (int i = 0; i < args.length; i++) {
ICPPTemplateParameter par= pars[i];
ICPPTemplateArgument arg = args[i];
if (par instanceof IType) {
if (arg.isNonTypeValue())
return false;
IType argType= arg.getTypeValue();
if (argType == null)
return false;
if (par.isParameterPack()) {
if (!(argType instanceof ICPPParameterPackType))
return false;
argType= ((ICPPParameterPackType) argType).getType();
if (argType == null)
return false;
}
if (!argType.isSameType((IType) par))
return false;
} else {
if (arg.isTypeValue())
return false;
if (par.isParameterPack() != arg.isPackExpansion())
return false;
int parpos= IntegralValue.isTemplateParameter(arg.getNonTypeValue());
if (parpos != par.getParameterID())
return false;
}
}
return true;
}
public static boolean hasDependentArgument(ICPPTemplateArgument[] args) {
for (ICPPTemplateArgument arg : args) {
if (isDependentArgument(arg))
return true;
}
return false;
}
public static boolean isDependentArgument(ICPPTemplateArgument arg) {
if (arg.isTypeValue())
return isDependentType(arg.getTypeValue());
ICPPEvaluation evaluation = arg.getNonTypeEvaluation();
return evaluation.isTypeDependent() || evaluation.isValueDependent();
}
public static boolean containsDependentType(List<IType> ts) {
for (IType t : ts) {
if (isDependentType(t))
return true;
}
return false;
}
public static boolean containsDependentType(IType[] ts) {
for (IType t : ts) {
if (isDependentType(t))
return true;
}
return false;
}
public static boolean isDependentType(IType t) {
while (true) {
if (t instanceof ICPPUnknownType)
return true;
if (t instanceof ICPPFunctionType) {
final ICPPFunctionType ft = (ICPPFunctionType) t;
if (containsDependentType(ft.getParameterTypes()))
return true;
t= ft.getReturnType();
} else if (t instanceof ICPPPointerToMemberType) {
ICPPPointerToMemberType ptmt= (ICPPPointerToMemberType) t;
if (isDependentType(ptmt.getMemberOfClass()))
return true;
t= ptmt.getType();
} else if (t instanceof ICPPParameterPackType) {
return true;
} else if (t instanceof ITypeContainer) {
if (t instanceof IArrayType) {
IValue asize= ((IArrayType) t).getSize();
if (asize != null && IntegralValue.isDependentValue(asize))
return true;
}
t= ((ITypeContainer) t).getType();
} else if (t instanceof InitializerListType) {
return ((InitializerListType) t).getEvaluation().isTypeDependent();
} else if (t instanceof IBinding) {
IBinding owner = ((IBinding) t).getOwner();
if (owner instanceof ICPPClassTemplate)
return true;
return (owner instanceof IType) && owner != t && isDependentType((IType) owner);
} else {
return false;
}
}
}
public static boolean containsDependentArg(ObjectMap tpMap) {
for (Object arg : tpMap.valueArray()) {
if (isDependentType((IType) arg))
return true;
}
return false;
}
/**
* Attempts to (partially) resolve an unknown binding with the given arguments.
*/
public static IBinding resolveUnknown(ICPPUnknownBinding unknown, InstantiationContext context)
throws DOMException {
if (unknown instanceof ICPPDeferredClassInstance) {
return resolveDeferredClassInstance((ICPPDeferredClassInstance) unknown, context);
}
if (unknown instanceof ICPPDeferredVariableInstance) {
return resolveDeferredVariableInstance((ICPPDeferredVariableInstance) unknown, context);
}
if (unknown instanceof ICPPUnknownMember) {
return resolveUnknownMember((ICPPUnknownMember) unknown, context);
}
if (unknown instanceof ICPPTemplateParameter && unknown instanceof IType) {
IType type= resolveTemplateTypeParameter((ICPPTemplateParameter) unknown, context);
if (type instanceof IBinding)
return (IBinding) type;
}
if (unknown instanceof TypeOfDependentExpression) {
IType type= instantiateType((IType) unknown, context);
if (type instanceof IBinding)
return (IBinding) type;
}
return unknown;
}
private static IBinding resolveUnknownMember(ICPPUnknownMember unknown, InstantiationContext context)
throws DOMException {
final IType ot0= unknown.getOwnerType();
if (ot0 == null)
return unknown;
IBinding result = unknown;
IType ot1 = instantiateType(ot0, context);
if (ot1 != null) {
ot1 = SemanticUtil.getUltimateType(ot1, false);
if (ot1 instanceof ICPPUnknownType) {
if (unknown instanceof ICPPUnknownMemberClassInstance) {
ICPPUnknownMemberClassInstance ucli= (ICPPUnknownMemberClassInstance) unknown;
ICPPTemplateArgument[] args0 = ucli.getArguments();
ICPPTemplateArgument[] args1 = instantiateArguments(args0, context, false);
if (args0 != args1 || !ot1.isSameType(ot0)) {
args1= SemanticUtil.getSimplifiedArguments(args1);
result= new CPPUnknownClassInstance(ot1, ucli.getNameCharArray(), args1);
}
} else if (!ot1.isSameType(ot0)) {
if (unknown instanceof ICPPUnknownMemberClass) {
result= new CPPUnknownMemberClass(ot1, unknown.getNameCharArray());
} else {
result= new CPPUnknownMethod(ot1, unknown.getNameCharArray());
}
}
} else if (ot1 instanceof ICPPClassType) {
IScope s = ((ICPPClassType) ot1).getCompositeScope();
if (s != null) {
result= CPPSemantics.resolveUnknownName(s, unknown, context.getPoint());
if (unknown instanceof ICPPUnknownMemberClassInstance &&
(result instanceof ICPPTemplateDefinition ||
result instanceof ICPPAliasTemplateInstance)) {
ICPPTemplateArgument[] args1 = instantiateArguments(
((ICPPUnknownMemberClassInstance) unknown).getArguments(), context, false);
if (result instanceof ICPPClassTemplate) {
result = instantiate((ICPPClassTemplate) result, args1, context.getPoint());
} else if (result instanceof ICPPAliasTemplate) {
result = instantiateAliasTemplate((ICPPAliasTemplate) result, args1,
context.getPoint());
} 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 = instantiateAliasTemplateInstance((ICPPAliasTemplateInstance) result,
args1, context.getPoint());
}
}
}
} else if (ot1 != ot0) {
return new ProblemBinding(new CPPASTName(unknown.getNameCharArray()), context.getPoint(),
IProblemBinding.SEMANTIC_BAD_SCOPE);
}
}
return result;
}
private static IBinding resolveDeferredClassInstance(ICPPDeferredClassInstance dci, InstantiationContext context) {
ICPPClassTemplate classTemplate = dci.getClassTemplate();
ICPPTemplateArgument[] arguments = dci.getTemplateArguments();
ICPPTemplateArgument[] newArgs;
try {
newArgs = instantiateArguments(arguments, context, true);
} catch (DOMException e) {
return e.getProblem();
}
if (newArgs == null)
return createProblem(classTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, context.getPoint());
boolean changed= arguments != newArgs;
IType classTemplateSpecialization= instantiateType(classTemplate, context);
if (classTemplateSpecialization != classTemplate && classTemplateSpecialization instanceof ICPPClassTemplate) {
classTemplate= (ICPPClassTemplate) classTemplateSpecialization;
changed= true;
}
if (changed) {
IBinding inst= instantiate(classTemplate, newArgs, context.getPoint());
if (inst != null)
return inst;
}
return dci;
}
private static IBinding resolveDeferredVariableInstance(ICPPDeferredVariableInstance dvi,
InstantiationContext context) {
ICPPVariableTemplate variableTemplate = dvi.getTemplateDefinition();
ICPPTemplateArgument[] arguments = dvi.getTemplateArguments();
ICPPTemplateArgument[] newArgs;
try {
newArgs = instantiateArguments(arguments, context, true);
} catch (DOMException e) {
return e.getProblem();
}
if (newArgs == null) {
return createProblem(variableTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS,
context.getPoint());
}
// Unlike class templates, variable templates cannot be passed as template template arguments,
// so there is no need to instantiate the template itself.
if (arguments != newArgs) {
IBinding inst = instantiate(variableTemplate, newArgs, context.getPoint());
if (inst != null)
return inst;
}
return dvi;
}
public static boolean haveSameArguments(ICPPTemplateInstance i1, ICPPTemplateInstance i2) {
final ICPPTemplateArgument[] m1= i1.getTemplateArguments();
final ICPPTemplateArgument[] m2= i2.getTemplateArguments();
if (m1 == null || m2 == null || m1.length != m2.length)
return false;
String s1 = ASTTypeUtil.getArgumentListString(m1, true);
String s2 = ASTTypeUtil.getArgumentListString(m2, true);
return s1.equals(s2);
}
/**
* Creates a template parameter map for the given template definition and template arguments. The template
* arguments are adjusted by converting types of the non-type arguments to match the types of the template
* parameters.
*
* @param template the template definition
* @param arguments the template arguments; arguments may be modified by this method due to type
* conversion performed for non-type arguments
* @param point the point of instantiation
* @return the created template parameter map, or {@code null} if the arguments are invalid
*/
private static CPPTemplateParameterMap createParameterMap(ICPPTemplateDefinition template,
ICPPTemplateArgument[] arguments, IASTNode point) {
final ICPPTemplateParameter[] parameters= template.getTemplateParameters();
final int numArgs = arguments.length;
final int numParams= parameters.length;
final int length= Math.max(numArgs, numParams);
CPPTemplateParameterMap map= new CPPTemplateParameterMap(numParams);
boolean isPack= false;
ICPPTemplateParameter param= null;
for (int i = 0; i < length; i++) {
if (!isPack || param == null) {
if (i >= numParams)
return null;
param= parameters[i];
isPack= param.isParameterPack();
}
if (i < numArgs) {
ICPPTemplateArgument arg= arguments[i];
ICPPTemplateArgument newArg =
matchTemplateParameterAndArgument(template, param, arg, map, point);
if (newArg == null)
return null;
if (newArg != arg) {
arguments[i]= newArg;
}
if (!isPack) {
map.put(param, newArg);
}
} else {
// Parameter pack with empty arguments.
assert isPack;
}
}
if (isPack) {
int packOffset= numParams - 1;
int packSize= numArgs - packOffset;
ICPPTemplateArgument[] pack= new ICPPTemplateArgument[packSize];
System.arraycopy(arguments, packOffset, pack, 0, packSize);
map.put(param, pack);
}
return map;
}
public static IBinding findDeclarationForSpecialization(IBinding binding) {
while (binding instanceof ICPPSpecialization) {
if (ASTInternal.hasDeclaration(binding))
return binding;
IBinding original= ((ICPPSpecialization) binding).getSpecializedBinding();
if (original == null)
return binding;
binding= original;
}
return binding;
}
/**
* Returns the instantiated function body of the given function specialization.
* @param point The point of instantiation for name lookups
*/
public static ICPPExecution instantiateFunctionBody(ICPPFunctionSpecialization f, IASTNode point) {
ICPPFunction spec = (ICPPFunction) f.getSpecializedBinding();
ICPPExecution exec = null;
if (spec instanceof ICPPComputableFunction) {
exec = ((ICPPComputableFunction) spec).getFunctionBodyExecution(point);
if (exec != null) {
InstantiationContext context = new InstantiationContext(f.getTemplateParameterMap(), f, point);
CPPTemplates.addInstantiatedParameters(context, f);
exec = exec.instantiate(context, IntegralValue.MAX_RECURSION_DEPTH);
}
}
return exec;
}
private static void addInstantiatedParameters(InstantiationContext context,
ICPPFunctionSpecialization spec) {
ICPPFunction specialized = (ICPPFunction) spec.getSpecializedBinding();
ICPPParameter paramSpecs[] = spec.getParameters();
ICPPParameter specializedParams[] = specialized.getParameters();
for (int i = 0; i < paramSpecs.length; i++) {
final ICPPParameter paramSpecialization = paramSpecs[i];
final ICPPParameter specializedParam = specializedParams[i];
context.putInstantiatedLocal(specializedParam, paramSpecialization);
if (specializedParam.isParameterPack()) {
break;
}
}
}
/**
* Returns the instantiated constructor chain of the given constructor specialization.
* @param point The point of instantiation for name lookups
*/
public static ICPPExecution instantiateConstructorChain(ICPPConstructorSpecialization f, IASTNode point) {
ICPPConstructor spec = (ICPPConstructor) f.getSpecializedBinding();
ICPPExecution exec = null;
if (spec != null) {
exec = spec.getConstructorChainExecution(point);
if (exec != null) {
InstantiationContext context = new InstantiationContext(f.getTemplateParameterMap(), f, point);
exec = exec.instantiate(context, IntegralValue.MAX_RECURSION_DEPTH);
}
}
return exec;
}
/**
* Instantiate a plain name (simple-id).
* Only destructor names require instantiation, e.g. the name "~T", when instantiated
* with a parameter map that maps T to C, needs to become "~C".
*
* @param name the name to be instantiated
* @param context the instantiation context
* @param enclosingTemplate The enclosing template definition. This is required because the
* instantiation context doesn't actually store parameter names, so
* we need to walk the chain of enclosing templates to find potential
* template parameter names.
* @return The instantiated name. If the provided name is not a destructor name, or if
* the type named by the destructor name is not mapped to anything in the
* instantiation context's parameter map, the provided name is returned unchanged.
*/
public static char[] instantiateName(char[] name, InstantiationContext context, IBinding enclosingTemplate) {
if (name == null || name.length == 0 || name[0] != '~') {
return name;
}
String typename = new String(name).substring(1);
ICPPTemplateParameterMap map = context.getParameterMap();
IBinding enclosing = enclosingTemplate;
while (enclosing != null) {
if (enclosing instanceof ICPPTemplateDefinition) {
for (ICPPTemplateParameter param : ((ICPPTemplateDefinition) enclosing).getTemplateParameters()) {
if (param instanceof ICPPTemplateTypeParameter) {
if (param.getName().equals(typename)) {
ICPPTemplateArgument arg = map.getArgument(param);
if (arg instanceof CPPTemplateTypeArgument) {
IType argType = arg.getTypeValue();
argType = SemanticUtil.getNestedType(argType, CVTYPE | TDEF);
if (argType instanceof ICPPClassType) {
StringBuilder result = new StringBuilder();
result.append('~');
result.append(((ICPPClassType) argType).getName());
return result.toString().toCharArray();
}
}
}
}
}
}
enclosing = enclosing.getOwner();
}
return name;
}
}