/*******************************************************************************
* Copyright (c) 2005, 2011 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)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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;
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.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTName;
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.IEnumeration;
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.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.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.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
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.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.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
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.ICPPParameterPackType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType;
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.ICPPUsingDeclaration;
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.CharArrayUtils;
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.IASTInternalScope;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
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.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.CPPFieldSpecialization;
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.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateDefinition;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeParameter;
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.CPPTemplateTypeParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTypedefSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownClass;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUsingDeclarationSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPASTInternalTemplateDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
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.ICPPUnknownClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
/**
* Collection of static methods to perform template instantiation, member specialization and
* type instantiation.
*/
public class CPPTemplates {
private static final int PACK_SIZE_DEFER = -1;
private static final int PACK_SIZE_FAIL = -2;
private static final int PACK_SIZE_NOT_FOUND = Integer.MAX_VALUE;
private static final ICPPFunction[] NO_FUNCTIONS = {};
static enum TypeSelection { PARAMETERS, RETURN_TYPE, PARAMETERS_AND_RETURN_TYPE }
/**
* Instantiates a class template with the given arguments. May return <code>null</code>.
*/
public static IBinding instantiate(ICPPClassTemplate template, ICPPTemplateArgument[] args) {
return instantiate(template, args, false, false);
}
/**
* Instantiates a class template with the given arguments. May return <code>null</code>.
*/
private static IBinding instantiate(ICPPClassTemplate template, ICPPTemplateArgument[] args,
boolean isDefinition, boolean isExplicitSpecialization) {
try {
// Add default arguments, if necessary.
ICPPTemplateArgument[] arguments= SemanticUtil.getSimplifiedArguments(args);
arguments= addDefaultArguments(template, arguments);
if (arguments == null)
return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS);
if (template instanceof ICPPTemplateTemplateParameter || hasDependentArgument(arguments)) {
return deferredInstance(template, arguments);
}
if (template instanceof ICPPClassTemplatePartialSpecialization) {
return instantiatePartialSpecialization((ICPPClassTemplatePartialSpecialization) template, arguments, isDefinition, null);
}
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) {
param= parameters[i];
isPack= param.isParameterPack();
} else {
return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS);
}
}
if (i < numArgs) {
ICPPTemplateArgument arg= arguments[i];
ICPPTemplateArgument newArg = CPPTemplates.matchTemplateParameterAndArgument(param, arg, map);
if (newArg == null)
return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS);
if (newArg != arg) {
if (arguments == args) {
arguments= args.clone();
}
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);
}
ICPPTemplateInstance prim= getInstance(template, arguments, isDefinition);
if (prim != null && (isExplicitSpecialization || prim.isExplicitSpecialization()))
return prim;
if (!isExplicitSpecialization) {
IBinding result= CPPTemplates.selectSpecialization(template, arguments, isDefinition);
if (result != null)
return result;
}
return instantiatePrimaryTemplate(template, arguments, map, isDefinition);
} catch (DOMException e) {
return e.getProblem();
}
}
private static IBinding createProblem(ICPPClassTemplate template, int id) {
IASTNode node= new CPPASTName(template.getNameCharArray());
return new ProblemBinding(node, id, template.getNameCharArray());
}
static IBinding isUsedInClassTemplateScope(ICPPClassTemplate ct, IASTName name) {
try {
IScope scope;
ICPPASTFunctionDefinition func= CPPVisitor.findEnclosingFunctionDefinition(name);
if (func != null) {
name= ASTQueries.findInnermostDeclarator(func.getDeclarator()).getName().getLastName();
scope= CPPVisitor.getContainingScope(name);
} else {
scope= CPPVisitor.getContainingScope(name);
if (!(scope instanceof IASTInternalScope))
return null;
}
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 CPPTemplates.instantiateWithinClassTemplate(ct);
}
if (b instanceof ICPPClassTemplatePartialSpecialization) {
ICPPClassTemplatePartialSpecialization pspec= (ICPPClassTemplatePartialSpecialization) b;
if (ct.isSameType(pspec.getPrimaryClassTemplate())) {
return CPPTemplates.instantiateWithinClassTemplate(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;
scope= CPPVisitor.getContainingScope(internalScope.getPhysicalNode());
if (scope == internalScope)
return null;
} else {
scope= scope.getParent();
}
}
} catch (DOMException e) {
}
return null;
}
private static IBinding instantiateFunctionTemplate(ICPPFunctionTemplate template,
ICPPTemplateArgument[] arguments, CPPTemplateParameterMap map) throws DOMException {
ICPPTemplateInstance instance= getInstance(template, arguments, false);
if (instance != null) {
return instance;
}
IBinding owner= template.getOwner();
instance = CPPTemplates.createInstance(owner, template, map, arguments);
addInstance(template, arguments, instance);
return instance;
}
/**
* Instantiates a partial class template specialization.
*/
private static IBinding instantiatePartialSpecialization(
ICPPClassTemplatePartialSpecialization partialSpec, ICPPTemplateArgument[] args, boolean isDef,
CPPTemplateParameterMap tpMap) 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))
return null;
}
instance= createInstance(partialSpec.getOwner(), partialSpec, tpMap, args);
addInstance(partialSpec, args, instance);
return instance;
}
/**
* Instantiates the selected template, without looking for specializations. May return <code>null</code>.
* @param map
*/
private static IBinding instantiatePrimaryTemplate(ICPPClassTemplate template, ICPPTemplateArgument[] arguments,
CPPTemplateParameterMap map, boolean isDef) throws DOMException {
assert !(template instanceof ICPPClassTemplatePartialSpecialization);
ICPPTemplateInstance instance= getInstance(template, arguments, isDef);
if (instance != null) {
return instance;
}
IBinding owner= template.getOwner();
instance = CPPTemplates.createInstance(owner, template, map, arguments);
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;
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(ICPPClassTemplate template, ICPPTemplateArgument[] arguments) throws DOMException {
ICPPTemplateInstance instance= getInstance(template, arguments, false);
if (instance != null)
return instance;
instance = new CPPDeferredClassInstance(template, arguments);
addInstance(template, arguments, instance);
return instance;
}
private static ICPPTemplateArgument[] addDefaultArguments(ICPPClassTemplate template,
ICPPTemplateArgument[] arguments) 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);
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, map, -1, null);
arg= SemanticUtil.getSimplifiedArgument(arg);
if (!isValidArgument(arg)) {
return null;
}
}
map.put(tpar, arg);
completeArgs[i]= arg;
}
return completeArgs;
}
/**
* Instantiates the template for usage within its own body. May return <code>null</code>.
*/
public static ICPPClassType instantiateWithinClassTemplate(ICPPClassTemplate template) throws DOMException {
ICPPTemplateInstance di= template.asDeferredInstance();
if (di instanceof ICPPClassType)
return (ICPPClassType) di;
ICPPTemplateArgument[] args;
if (template instanceof ICPPClassTemplatePartialSpecialization) {
args= ((ICPPClassTemplatePartialSpecialization) template).getTemplateArguments();
} else {
ICPPTemplateParameter[] templateParameters = template.getTemplateParameters();
args = templateParametersAsArguments(templateParameters);
}
IBinding result = deferredInstance(template, args);
if (result instanceof ICPPClassType)
return (ICPPClassType) result;
return template;
}
public static ICPPTemplateArgument[] templateParametersAsArguments(
ICPPTemplateParameter[] templateParameters) throws DOMException {
ICPPTemplateArgument[] args;
args = new ICPPTemplateArgument[templateParameters.length];
for (int i = 0; i < templateParameters.length; i++) {
final ICPPTemplateParameter tp = templateParameters[i];
if (tp instanceof IType) {
IType t= (IType) tp;
if (tp.isParameterPack()) {
t= new CPPParameterPackType(t);
}
args[i] = new CPPTemplateArgument(t);
} else if (tp instanceof ICPPTemplateNonTypeParameter) {
// Non-type template parameter pack already has type 'ICPPParameterPackType'
final ICPPTemplateNonTypeParameter nttp = (ICPPTemplateNonTypeParameter) tp;
args[i] = new CPPTemplateArgument(Value.create(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 = (ICPPASTTemplateDeclaration[]) ArrayUtil.append(ICPPASTTemplateDeclaration.class, templates, parent);
}
templates = (ICPPASTTemplateDeclaration[]) 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();
}
if (name == null)
return null;
if (name instanceof ICPPASTQualifiedName) {
int idx = templates.length;
int i = 0;
IASTName[] ns = ((ICPPASTQualifiedName) name).getNames();
for (IASTName element : ns) {
if (element instanceof ICPPASTTemplateId) {
++i;
if (i == idx) {
binding = ((ICPPASTTemplateId) element).resolveBinding();
break;
}
}
}
if (binding == null)
binding = ns[ns.length - 1].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) {
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;
}
if (isDeclaration || isDefinition) {
IASTNode parentOfDeclaration = declaration.getParent();
if (parentOfDeclaration instanceof ICPPASTExplicitTemplateInstantiation) {
isDeclaration= false;
} else if (parentOfDeclaration instanceof ICPPASTTemplateSpecialization) {
isExplicitSpecialization= true;
}
}
}
}
try {
// class template instance
IBinding result= null;
IASTName templateName = id.getTemplateName();
IBinding template = templateName.resolvePreBinding();
if (template instanceof ICPPConstructor) {
template= template.getOwner();
}
if (template instanceof ICPPUnknownClassType) {
IBinding owner= template.getOwner();
if (owner instanceof ICPPUnknownBinding) {
ICPPTemplateArgument[] args= createTemplateArgumentArray(id);
args= SemanticUtil.getSimplifiedArguments(args);
return new CPPUnknownClassInstance((ICPPUnknownBinding) template.getOwner(), id.getSimpleID(), args);
}
}
if (!(template instanceof ICPPClassTemplate) || template instanceof ICPPClassTemplatePartialSpecialization)
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TYPE, templateName.toCharArray());
final ICPPClassTemplate classTemplate = (ICPPClassTemplate) template;
ICPPTemplateArgument[] args= createTemplateArgumentArray(id);
if (hasDependentArgument(args)) {
ICPPASTTemplateDeclaration tdecl= getTemplateDeclaration(id);
if (tdecl != null) {
if (argsAreTrivial(classTemplate.getTemplateParameters(), args)) {
result= classTemplate;
} else {
ICPPClassTemplatePartialSpecialization partialSpec= findPartialSpecialization(classTemplate, args);
if (isDeclaration || isDefinition) {
if (partialSpec == null) {
partialSpec = new CPPClassTemplatePartialSpecialization(id);
if (template instanceof ICPPInternalClassTemplate)
((ICPPInternalClassTemplate) template).addPartialSpecialization(partialSpec);
return partialSpec;
}
}
if (partialSpec == null)
return new ProblemBinding(id, IProblemBinding.SEMANTIC_INVALID_TYPE, templateName.toCharArray());
result= partialSpec;
}
}
}
if (result == null) {
result= instantiate(classTemplate, args, isDefinition, isExplicitSpecialization);
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();
}
}
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,
CPPTemplateParameterMap tpMap, ICPPTemplateArgument[] args) {
if (owner instanceof ICPPSpecialization) {
ICPPTemplateParameterMap map= ((ICPPSpecialization) owner).getTemplateParameterMap();
if (map != null) {
tpMap.putAll(map);
}
}
ICPPTemplateInstance instance = null;
if (template instanceof ICPPClassType) {
instance = new CPPClassInstance((ICPPClassType) template, owner, tpMap, args);
} else if (owner instanceof ICPPClassType && template instanceof ICPPMethod) {
if (template instanceof ICPPConstructor) {
instance = new CPPConstructorInstance((ICPPConstructor) template, (ICPPClassType) owner, tpMap, args);
} else {
instance = new CPPMethodInstance((ICPPMethod) template, (ICPPClassType) owner, tpMap, args);
}
} else if (template instanceof ICPPFunction) {
instance = new CPPFunctionInstance((ICPPFunction) template, owner, tpMap, args);
}
return instance;
}
public static IBinding createSpecialization(ICPPClassSpecialization owner, IBinding decl) {
IBinding spec = null;
final ICPPTemplateParameterMap tpMap= owner.getTemplateParameterMap();
if (decl instanceof ICPPClassTemplatePartialSpecialization) {
try {
ICPPClassTemplatePartialSpecialization pspec= (ICPPClassTemplatePartialSpecialization) decl;
ICPPClassTemplate template= (ICPPClassTemplate) owner.specializeMember(pspec.getPrimaryClassTemplate());
spec= new CPPClassTemplatePartialSpecializationSpecialization(pspec, template, tpMap);
} catch (DOMException e) {
}
} else if (decl instanceof ICPPClassTemplate) {
spec = new CPPClassTemplateSpecialization((ICPPClassTemplate) decl, owner, tpMap);
} else if (decl instanceof ICPPClassType) {
spec = new CPPClassSpecialization((ICPPClassType) decl, owner, tpMap);
} else if (decl instanceof ICPPField) {
spec = new CPPFieldSpecialization(decl, owner, tpMap);
} else if (decl instanceof ICPPFunctionTemplate) {
if (decl instanceof ICPPConstructor)
spec = new CPPConstructorTemplateSpecialization((ICPPConstructor) decl, owner, tpMap);
else if (decl instanceof ICPPMethod)
spec = new CPPMethodTemplateSpecialization((ICPPMethod) decl, owner, tpMap);
else
spec = new CPPFunctionTemplateSpecialization((ICPPFunctionTemplate) decl, owner, tpMap);
} else if (decl instanceof ICPPConstructor) {
spec = new CPPConstructorSpecialization((ICPPConstructor) decl, owner, tpMap);
} else if (decl instanceof ICPPMethod) {
spec = new CPPMethodSpecialization((ICPPMethod) decl, owner, tpMap);
} else if (decl instanceof ICPPFunction) {
spec = new CPPFunctionSpecialization((ICPPFunction) decl, owner, tpMap);
} else if (decl instanceof ITypedef) {
spec = new CPPTypedefSpecialization(decl, owner, tpMap);
} else if (decl instanceof IEnumeration || decl instanceof IEnumerator) {
// TODO(sprigogin): Deal with a case when an enumerator value depends on a template parameter.
spec = decl;
} else if (decl instanceof ICPPUsingDeclaration) {
spec= new CPPUsingDeclarationSpecialization((ICPPUsingDeclaration) decl, owner, tpMap);
}
return spec;
}
public static IValue instantiateValue(IValue value, ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within, int maxdepth) {
if (value == null)
return null;
IBinding[] unknowns= value.getUnknownBindings();
IBinding[] resolvedUnknowns= null;
if (unknowns.length != 0) {
for (int i = 0; i < unknowns.length; i++) {
IBinding unknown= unknowns[i];
IBinding resolved= unknown;
if (unknown instanceof ICPPUnknownBinding) {
try {
resolved= resolveUnknown((ICPPUnknownBinding) unknown, tpMap, packOffset, within);
} catch (DOMException e) {
return Value.UNKNOWN;
}
}
if (resolvedUnknowns != null) {
resolvedUnknowns[i]= resolved;
} else if (resolved != unknown) {
resolvedUnknowns= new IBinding[unknowns.length];
System.arraycopy(unknowns, 0, resolvedUnknowns, 0, i);
resolvedUnknowns[i]= resolved;
}
}
}
if (resolvedUnknowns != null)
return Value.reevaluate(value, packOffset, resolvedUnknowns, tpMap, maxdepth);
if (Value.referencesTemplateParameter(value))
return Value.reevaluate(value, packOffset, unknowns, tpMap, maxdepth);
return value;
}
public static boolean containsParameterPack(IType type) {
return determinePackSize(type, CPPTemplateParameterMap.EMPTY) == PACK_SIZE_DEFER;
}
private 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= combine(r, determinePackSize(pt, tpMap));
if (r < 0)
return r;
}
return r;
}
if (type instanceof ICPPTemplateParameter) {
final ICPPTemplateParameter tpar = (ICPPTemplateParameter) type;
if (tpar.isParameterPack()) {
ICPPTemplateArgument[] args= tpMap.getPackExpansion(tpar);
if (args != null)
return args.length;
return PACK_SIZE_DEFER;
}
return PACK_SIZE_NOT_FOUND;
}
int r= PACK_SIZE_NOT_FOUND;
if (type instanceof ICPPUnknownBinding) {
if (type instanceof ICPPDeferredClassInstance) {
ICPPDeferredClassInstance dcl= (ICPPDeferredClassInstance) type;
ICPPTemplateArgument[] args = dcl.getTemplateArguments();
for (ICPPTemplateArgument arg : args) {
r= combine(r, determinePackSize(arg, tpMap));
if (r < 0)
return r;
}
}
IBinding binding= ((ICPPUnknownBinding) type).getOwner();
if (binding instanceof IType)
r= combine(r, determinePackSize((IType) binding, tpMap));
return r;
}
if (type instanceof ICPPParameterPackType)
return 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= combine(r, determinePackSize(typeContainer.getType(), tpMap));
}
return r;
}
private static int combine(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;
}
private static int determinePackSize(IValue value, ICPPTemplateParameterMap tpMap) {
int r= PACK_SIZE_NOT_FOUND;
IBinding[] unknown= value.getUnknownBindings();
for (IBinding binding : unknown) {
if (binding instanceof IType) {
r= combine(r, determinePackSize((IType) binding, tpMap));
if (r < 0)
return r;
}
}
int[] tpars= Value.getParameterPackReferences(value);
for (int parID : tpars) {
ICPPTemplateArgument[] args= tpMap.getPackExpansion(parID);
if (args != null) {
r= combine(r, args.length);
if (r < 0)
return r;
}
return PACK_SIZE_DEFER;
}
return r;
}
private static int determinePackSize(ICPPTemplateArgument arg, ICPPTemplateParameterMap tpMap) {
if (arg.isTypeValue())
return determinePackSize(arg.getTypeValue(), tpMap);
return determinePackSize(arg.getNonTypeValue(), tpMap);
}
/**
* Instantiates types contained in an array.
* @param types an array of types
* @param tpMap template argument map
* @return an array containing instantiated types.
*/
public static IType[] instantiateTypes(IType[] types, ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) {
// 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) {
origType= ((ICPPParameterPackType) origType).getType();
int packSize= determinePackSize(origType, tpMap);
if (packSize == PACK_SIZE_FAIL || packSize == PACK_SIZE_NOT_FOUND) {
newType= new ProblemBinding(null, IProblemBinding.SEMANTIC_INVALID_TYPE);
} 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;
for(int k=0; k<packSize; k++) {
result[j++]= CPPTemplates.instantiateType(origType, tpMap, k, within);
}
continue;
}
} else {
newType = CPPTemplates.instantiateType(origType, tpMap, packOffset, within);
}
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.
*/
public static ICPPTemplateArgument[] instantiateArguments(ICPPTemplateArgument[] args,
ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within)
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()) {
origArg= origArg.getExpansionPattern();
int packSize= determinePackSize(origArg, tpMap);
if (packSize == PACK_SIZE_FAIL || packSize == PACK_SIZE_NOT_FOUND) {
throw new DOMException(new ProblemBinding(null, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS));
} else if (packSize == PACK_SIZE_DEFER) {
newArg= origArg;
} else {
final int shift = packSize-1;
ICPPTemplateArgument[] newResult= new ICPPTemplateArgument[args.length + resultShift + shift];
System.arraycopy(result, 0, newResult, 0, i+resultShift);
for(int j=0; j<packSize; j++) {
newResult[i+resultShift+j]= CPPTemplates.instantiateArgument(origArg, tpMap, j, within);
}
result= newResult;
resultShift+= shift;
continue;
}
} else {
newArg = CPPTemplates.instantiateArgument(origArg, tpMap, packOffset, within);
}
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 an argument
*/
static ICPPTemplateArgument instantiateArgument(ICPPTemplateArgument arg,
ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) {
if (arg == null)
return null;
if (arg.isNonTypeValue()) {
final IValue origValue= arg.getNonTypeValue();
final IType origType= arg.getTypeOfNonTypeValue();
final IValue instValue= instantiateValue(origValue, tpMap, packOffset, within, Value.MAX_RECURSION_DEPTH);
final IType instType= instantiateType(origType, tpMap, packOffset, within);
if (origType == instType && origValue == instValue)
return arg;
return new CPPTemplateArgument(instValue, instType);
}
final IType orig= arg.getTypeValue();
final IType inst= instantiateType(orig, tpMap, packOffset, within);
if (orig == inst)
return arg;
return new CPPTemplateArgument(inst);
}
/**
* This method propagates the specialization of a member to the types used by the member.
* @param type a type to instantiate.
* @param tpMap a mapping between template parameters and the corresponding arguments.
*/
public static IType instantiateType(IType type, ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) {
try {
if (tpMap == null)
return type;
if (type instanceof ICPPFunctionType) {
final ICPPFunctionType ft = (ICPPFunctionType) type;
IType ret = null;
IType[] params = null;
final IType r = ft.getReturnType();
ret = instantiateType(r, tpMap, packOffset, within);
IType[] ps = ft.getParameterTypes();
params = instantiateTypes(ps, tpMap, packOffset, within);
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.takesVarArgs());
}
if (type instanceof ICPPTemplateParameter) {
final ICPPTemplateParameter tpar = (ICPPTemplateParameter) type;
ICPPTemplateArgument arg= null;
if (tpar.isParameterPack()) {
if (packOffset >= 0) {
ICPPTemplateArgument[] args = tpMap.getPackExpansion(tpar);
if (args != null) {
if (packOffset >= args.length) {
return new ProblemBinding(null, IProblemBinding.SEMANTIC_INVALID_TYPE);
}
arg= args[packOffset];
}
}
} else {
arg= tpMap.getArgument(tpar);
}
if (arg != null) {
IType t= arg.getTypeValue();
if (t != null)
return t;
}
return type;
}
if (type instanceof ICPPUnknownBinding) {
IBinding binding= resolveUnknown((ICPPUnknownBinding) type, tpMap, packOffset, within);
if (binding instanceof IType)
return (IType) binding;
return type;
}
if (within != null && type instanceof IBinding &&
(type instanceof ITypedef || type instanceof ICPPClassType)) {
ICPPClassType originalClass= within.getSpecializedBinding();
if (originalClass.isSameType(type))
return within;
IBinding typeAsBinding= (IBinding) type;
IBinding typeOwner= typeAsBinding.getOwner();
if (typeOwner instanceof IType) {
IType newOwner= instantiateType((IType) typeOwner, tpMap, packOffset, within);
if (newOwner != typeOwner && newOwner instanceof ICPPClassSpecialization) {
return (IType) ((ICPPClassSpecialization) newOwner).specializeMember(typeAsBinding);
}
return type;
}
}
if (type instanceof ITypeContainer) {
final ITypeContainer typeContainer = (ITypeContainer) type;
IType nestedType = typeContainer.getType();
IType newNestedType = instantiateType(nestedType, tpMap, packOffset, within);
if (typeContainer instanceof ICPPPointerToMemberType) {
ICPPPointerToMemberType ptm = (ICPPPointerToMemberType) typeContainer;
IType memberOfClass = ptm.getMemberOfClass();
IType newMemberOfClass = instantiateType(memberOfClass, tpMap, packOffset, within);
if (!(newMemberOfClass instanceof ICPPClassType || newMemberOfClass instanceof UniqueType
|| newMemberOfClass instanceof ICPPUnknownBinding)) {
newMemberOfClass = memberOfClass;
}
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, tpMap, packOffset, within, Value.MAX_RECURSION_DEPTH);
if (newSize != asize) {
return new CPPArrayType(newNestedType, newSize);
}
}
}
if (newNestedType != nestedType) {
return SemanticUtil.replaceNestedType(typeContainer, newNestedType);
}
return typeContainer;
}
return type;
} catch (DOMException e) {
return e.getProblem();
}
}
/**
* 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 <typename T> void MyTemplate<T>::member() {}
* </pre>
* @param name a name for which the corresponding template declaration is searched for.
* @return the template declaration or <code>null</code> if <code>name</code> 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 IASTName[] ns= qname.getNames();
for (int i = ns.length-2; tdecl != null && i >= 0; i--) {
final IASTName n = ns[i];
if (n == name) {
return tdecl;
}
if (n instanceof ICPPASTTemplateId) {
tdecl= getDirectlyEnclosingTemplateDeclaration(tdecl);
}
}
// not enough template declartaions
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
IASTName name= getNameForDeclarationInTemplateDeclaration(decl);
// count template declarations
int tdeclcount= 1;
IASTNode node= tdecl.getParent();
while (node instanceof ICPPASTInternalTemplateDeclaration) {
tdeclcount++;
tdecl = (ICPPASTInternalTemplateDeclaration) node;
node= node.getParent();
}
final ICPPASTInternalTemplateDeclaration outerMostTDecl= tdecl;
// determine association of names with template declarations
boolean lastIsTemplate= true;
int missingTemplateDecls= 0;
if (name instanceof ICPPASTQualifiedName) {
ICPPASTQualifiedName qname= (ICPPASTQualifiedName) name;
final IASTName lastName = qname.getLastName();
final boolean lastIsID = lastName instanceof ICPPASTTemplateId;
// count template-ids
int idcount= 0;
final IASTName[] ns= qname.getNames();
for (final IASTName n : ns) {
if (n instanceof ICPPASTTemplateId) {
idcount++;
}
}
boolean isCtorWithTemplateID= false;
if (lastIsID && ns.length > 1) {
IASTName secondLastName= ns[ns.length-2];
if (secondLastName instanceof ICPPASTTemplateId) {
final char[] lastNamesLookupKey = lastName.getLookupKey();
if (CharArrayUtils.equals(lastNamesLookupKey, ((ICPPASTTemplateId) secondLastName).getLookupKey()) ||
(lastNamesLookupKey.length > 0 && lastNamesLookupKey[0] == '~')) {
isCtorWithTemplateID= true;
idcount--;
}
}
}
if (lastIsID && !isCtorWithTemplateID) {
missingTemplateDecls= idcount-tdeclcount;
} else {
missingTemplateDecls= idcount+1-tdeclcount;
if (missingTemplateDecls > 0) {
// last name is probably not a template
missingTemplateDecls--;
lastIsTemplate= false;
CharArraySet tparnames= collectTemplateParameterNames(outerMostTDecl);
int j= 0;
for (IASTName n : ns) {
if (n instanceof ICPPASTTemplateId) {
// if we find a dependent id, there can be no explicit specialization.
ICPPASTTemplateId id= (ICPPASTTemplateId) n;
if (usesTemplateParameter(id, tparnames))
break;
if (j++ == missingTemplateDecls) {
IBinding b= n.resolveBinding();
if (b instanceof ICPPTemplateInstance && b instanceof ICPPClassType) {
if (((ICPPTemplateInstance) b).isExplicitSpecialization()) {
// For a template-id of an explicit specialization.
// we don't have a template declaration. (see 14.7.3.5)
missingTemplateDecls++;
lastIsTemplate= true;
}
}
break;
}
}
}
}
}
}
if (missingTemplateDecls < 0) {
missingTemplateDecls= 0; // too many template declarations
}
// determine nesting level of parent
int level= missingTemplateDecls;
if (!isFriendFunctionDeclaration(innerMostTDecl.getDeclaration())) {
node= outerMostTDecl.getParent();
while (node != null) {
if (node instanceof ICPPASTInternalTemplateDeclaration) {
level+= ((ICPPASTInternalTemplateDeclaration) node).getNestingLevel() + 1;
break;
}
node= node.getParent();
}
}
tdecl= outerMostTDecl;
while(true) {
tdecl.setNestingLevel((short) level++);
tdecl.setAssociatedWithLastName(false);
node= tdecl.getDeclaration();
if (node instanceof ICPPASTInternalTemplateDeclaration) {
tdecl= (ICPPASTInternalTemplateDeclaration) node;
} else {
break;
}
}
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= CPPTemplates.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) {
if (((ICPPASTQualifiedName) parent).getNames()[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) {
IASTName[] ns = ((ICPPASTQualifiedName) name).getNames();
IASTDeclaration currDecl = decl;
for (int j = 0; j < ns.length; j++) {
if (ns[j] instanceof ICPPASTTemplateId || j + 1 == ns.length) {
if (currDecl == templateDecl) {
return ns[j];
}
if (currDecl instanceof ICPPASTTemplateDeclaration) {
currDecl = ((ICPPASTTemplateDeclaration) currDecl).getDeclaration();
} else {
return null;
}
}
}
} 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 IType array is returned if id is <code>null</code>
*/
public static ICPPTemplateArgument[] createTemplateArgumentArray(ICPPASTTemplateId id) {
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 CPPTemplateArgument(CPPVisitor.createType((IASTTypeId) arg));
} else if (arg instanceof IASTExpression) {
IASTExpression expr= (IASTExpression) arg;
IType type= expr.getExpressionType();
IValue value= Value.create((IASTExpression) arg, Value.MAX_RECURSION_DEPTH);
result[i]= new CPPTemplateArgument(value, type);
} else {
throw new IllegalArgumentException();
}
}
}
return result;
}
static ICPPFunction[] instantiateForFunctionCall(IASTName name, ICPPFunction[] fns,
List<IType> fnArgs, List<ValueCategory> argCats, boolean withImpliedObjectArg) {
if (name != null && name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
name= (IASTName) name.getParent();
}
// Extract template arguments.
ICPPTemplateArgument[] tmplArgs= ICPPTemplateArgument.EMPTY_ARGUMENTS;
boolean requireTemplate= name instanceof ICPPASTTemplateId;
boolean haveTemplate= false;
for (final ICPPFunction func : fns) {
if (func instanceof ICPPConstructor || (func instanceof ICPPMethod && ((ICPPMethod) func).isDestructor()))
requireTemplate= false;
if (func instanceof ICPPFunctionTemplate) {
ICPPFunctionTemplate template= (ICPPFunctionTemplate) func;
try {
if (containsDependentType(fnArgs))
return new ICPPFunction[] {CPPUnknownFunction.createForSample(template)};
if (requireTemplate) {
tmplArgs = createTemplateArgumentArray((ICPPASTTemplateId) name);
if (hasDependentArgument(tmplArgs))
return new ICPPFunction[] {CPPUnknownFunction.createForSample(template)};
}
} catch (DOMException e) {
return NO_FUNCTIONS;
}
haveTemplate= true;
break;
}
}
if (!haveTemplate && !requireTemplate)
return fns;
final List<ICPPFunction> result= new ArrayList<ICPPFunction>(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);
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) {
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);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map);
if (instance instanceof ICPPFunction) {
final ICPPFunction f = (ICPPFunction) instance;
if (isValidType(f.getType()))
return f;
}
}
} catch (DOMException e) {
}
return null;
}
/**
* 14.8.2.3 Deducing conversion function template arguments
*/
static ICPPFunction[] instantiateConversionTemplates(ICPPFunction[] functions, IType conversionType) {
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) {
try {
if (isDependentType(conversionType)) {
inst= CPPUnknownFunction.createForSample(template);
done= true;
}
checkedForDependentType= true;
} catch (DOMException e) {
return functions;
}
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(1);
try {
ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForConversion(template, conversionType, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map);
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
* @return
*/
static ICPPFunction instantiateForFunctionDeclaration(ICPPFunctionTemplate template,
ICPPTemplateArgument[] args, ICPPFunctionType functionType) {
CPPTemplateParameterMap map= new CPPTemplateParameterMap(1);
try {
args= TemplateArgumentDeduction.deduceForDeclaration(template, args, functionType, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map);
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, IASTName name) {
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
name= (IASTName) name.getParent();
}
try {
if (target != null && isDependentType(target)) {
return CPPUnknownFunction.createForSample(template);
}
ICPPTemplateArgument[] tmplArgs;
if (name instanceof ICPPASTTemplateId && !(template instanceof ICPPConstructor)) {
tmplArgs = createTemplateArgumentArray((ICPPASTTemplateId) name);
if (hasDependentArgument(tmplArgs)) {
return CPPUnknownFunction.createForSample(template);
}
} else {
tmplArgs= ICPPTemplateArgument.EMPTY_ARGUMENTS;
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(4);
ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForAddressOf(template, tmplArgs, target, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map);
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)
throws DOMException {
if (f1 == f2)
return 0;
if (f1 == null)
return -1;
if (f2 == null)
return 1;
int s1 = compareSpecialization(f1, f2, mode);
int s2 = compareSpecialization(f2, f1, mode);
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) 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 CPPTemplateArgument 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);
if (result instanceof ICPPFunction)
return (ICPPFunction) result;
return null;
}
private static CPPTemplateArgument uniqueArg(final ICPPTemplateParameter tpar) throws DOMException {
final CPPTemplateArgument arg;
if (tpar instanceof ICPPTemplateNonTypeParameter) {
arg = new CPPTemplateArgument(Value.unique(), ((ICPPTemplateNonTypeParameter) tpar).getType());
} else {
arg = new CPPTemplateArgument(new UniqueType(tpar.isParameterPack()));
}
return arg;
}
private static int compareSpecialization(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2, TypeSelection mode) throws DOMException {
ICPPFunction transF1 = transferFunctionTemplate(f1);
if (transF1 == null)
return -1;
final ICPPFunctionType ft2 = f2.getType();
final ICPPFunctionType transFt1 = transF1.getType();
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= concat(ft2.getReturnType(), ft2.getParameterTypes());
args= concat(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= addImplicitParameterType(args, (ICPPMethod) f1);
} else {
pars= addImplicitParameterType(pars, (ICPPMethod) f2);
}
}
break;
}
return TemplateArgumentDeduction.deduceForPartialOrdering(f2.getTemplateParameters(), pars, args);
}
private static boolean isNonStaticMember(ICPPFunctionTemplate f) {
return (f instanceof ICPPMethod) && !((ICPPMethod) f).isStatic();
}
private static IType[] addImplicitParameterType(IType[] types, ICPPMethod m) {
try {
IType t= CPPSemantics.getImplicitParameterType(m);
return concat(t, types);
} catch (DOMException e) {
return types;
}
}
private static IType[] concat(final IType t, IType[] types) {
IType[] result= new IType[types.length+1];
result[0]= t;
System.arraycopy(types, 0, result, 1, types.length);
return result;
}
private static ICPPClassTemplatePartialSpecialization findPartialSpecialization(ICPPClassTemplate ct,
ICPPTemplateArgument[] args) throws DOMException {
ICPPClassTemplatePartialSpecialization[] pspecs = ct.getPartialSpecializations();
if (pspecs != null && pspecs.length > 0) {
final String argStr= ASTTypeUtil.getArgumentListString(args, true);
for (ICPPClassTemplatePartialSpecialization pspec : pspecs) {
try {
if (argStr.equals(ASTTypeUtil.getArgumentListString(pspec.getTemplateArguments(), true)))
return pspec;
} catch (DOMException e) {
// ignore partial specializations with problems
}
}
}
return null;
}
private static IBinding selectSpecialization(ICPPClassTemplate template, ICPPTemplateArgument[] args,
boolean isDef) throws DOMException {
if (template == null) {
return null;
}
ICPPClassTemplatePartialSpecialization[] specializations = template.getPartialSpecializations();
if (specializations == null || specializations.length == 0) {
return null;
}
ICPPClassTemplatePartialSpecialization bestMatch = null, spec = null;
CPPTemplateParameterMap bestMap= null;
boolean bestMatchIsBest = true;
for (ICPPClassTemplatePartialSpecialization specialization : specializations) {
spec = specialization;
final CPPTemplateParameterMap map = new CPPTemplateParameterMap(args.length);
if (TemplateArgumentDeduction.fromTemplateArguments(spec.getTemplateParameters(), spec.getTemplateArguments(), args, map)) {
int compare = orderSpecializations(bestMatch, spec);
if (compare == 0) {
bestMatchIsBest = false;
} else if (compare < 0) {
bestMatch = spec;
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(null, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, null);
}
if (bestMatch == null)
return null;
return instantiatePartialSpecialization(bestMatch, args, isDef, bestMap);
}
/**
* Compare spec1 to spec2. Return > 0 if spec1 is more specialized, < 0 if spec2
* is more specialized, = 0 otherwise.
* @param spec1
* @param spec2
* @return
* @throws DOMException
*/
static private int orderSpecializations(ICPPClassTemplatePartialSpecialization spec1, ICPPClassTemplatePartialSpecialization spec2) 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);
boolean f2IsAtLeastAsSpecializedAsF1 = isAtLeastAsSpecializedAs(spec2, spec1);
if (f1IsAtLeastAsSpecializedAsF2 == f2IsAtLeastAsSpecializedAsF1)
return 0;
if (f1IsAtLeastAsSpecializedAsF2)
return 1;
return -1;
}
private static boolean isAtLeastAsSpecializedAs(ICPPClassTemplatePartialSpecialization f1, ICPPClassTemplatePartialSpecialization f2) 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();
if (targs1.length != targs2.length)
return false;
// 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 CPPTemplateArgument arg = uniqueArg(param);
args[i]= arg;
transferMap.put(param, arg);
}
final ICPPTemplateArgument[] transferredArgs1 = instantiateArguments(targs1, transferMap, -1, null);
// Deduce arguments for specialization 2
final CPPTemplateParameterMap deductionMap= new CPPTemplateParameterMap(2);
if (!TemplateArgumentDeduction.fromTemplateArguments(tpars2, targs2, transferredArgs1, deductionMap))
return false;
// Compare
for (int i = 0; i < targs2.length; i++) {
ICPPTemplateArgument transferredArg2= instantiateArgument(targs2[i], deductionMap, -1, null);
if (!transferredArg2.isSameValue(transferredArgs1[i]))
return false;
}
return true;
}
static boolean isValidType(IType t) {
for (;;) {
if (t instanceof ISemanticProblem) {
return false;
} else if (t instanceof IFunctionType) {
IFunctionType ft= (IFunctionType) t;
for (IType parameterType : ft.getParameterTypes()) {
if (!isValidType(parameterType))
return false;
}
t= ft.getReturnType();
} else if (t instanceof ICPPPointerToMemberType) {
ICPPPointerToMemberType mptr= (ICPPPointerToMemberType) t;
if (!isValidType(mptr.getMemberOfClass()))
return false;
t= mptr.getType();
} else if (t instanceof ITypeContainer) {
t= ((ITypeContainer) t).getType();
} else {
return true;
}
}
}
static boolean isValidArgument(ICPPTemplateArgument arg) {
return arg != null && isValidType(arg.isTypeValue() ? arg.getTypeValue() : arg.getTypeOfNonTypeValue());
}
static ICPPTemplateArgument matchTemplateParameterAndArgument(ICPPTemplateParameter param,
ICPPTemplateArgument arg, CPPTemplateParameterMap map) {
if (arg == null || !isValidType(arg.getTypeValue())) {
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();
if (!(t instanceof ICPPTemplateDefinition))
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, map, -1, null);
}
if (argType instanceof ICPPUnknownType || argType instanceof ISemanticProblem || isNonTypeArgumentConvertible(pType, argType)) {
return new CPPTemplateArgument(arg.getNonTypeValue(), pType);
}
return null;
} 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;
}
/**
* Returns whether the template argument <code>arg</code> can be converted to
* the same type as <code>paramType</code> using the rules specified in 14.3.2.5.
* @param paramType
* @param arg
* @return
* @throws DOMException
*/
private static boolean isNonTypeArgumentConvertible(IType paramType, IType arg) throws DOMException {
//14.1s8 function to pointer and array to pointer conversions
if (paramType instanceof IFunctionType) {
paramType = new CPPPointerType(paramType);
} else if (paramType instanceof IArrayType) {
paramType = new CPPPointerType(((IArrayType) paramType).getType());
}
Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, LVALUE, UDCMode.FORBIDDEN, Context.ORDINARY);
return cost != null && cost.converts();
}
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;
int parpos= Value.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());
return Value.isDependentValue(arg.getNonTypeValue());
}
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 && Value.isDependentValue(asize))
return true;
}
t= ((ITypeContainer) t).getType();
} else if (t instanceof InitializerListType) {
return isDependentInitializerList(((InitializerListType) t).getInitializerList());
} else {
return false;
}
}
}
private static boolean isDependentInitializerList(ICPPASTInitializerList initializerList) {
IASTInitializerClause[] clauses= initializerList.getClauses();
for (IASTInitializerClause clause : clauses) {
if (clause instanceof IASTExpression) {
IType t= ((IASTExpression) clause).getExpressionType();
if (isDependentType(t))
return true;
} else if (clause instanceof ICPPASTInitializerList) {
if (isDependentInitializerList((ICPPASTInitializerList) clause))
return true;
}
}
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, ICPPTemplateParameterMap tpMap,
int packOffset, ICPPClassSpecialization within) throws DOMException {
if (unknown instanceof ICPPDeferredClassInstance) {
return resolveDeferredClassInstance((ICPPDeferredClassInstance) unknown, tpMap, packOffset, within);
}
final IBinding owner= unknown.getOwner();
if (!(owner instanceof ICPPTemplateTypeParameter || owner instanceof ICPPUnknownClassType))
return unknown;
IBinding result = unknown;
IType t = CPPTemplates.instantiateType((IType) owner, tpMap, packOffset, within);
if (t != null) {
t = SemanticUtil.getUltimateType(t, false);
if (t instanceof ICPPUnknownBinding) {
if (unknown instanceof ICPPUnknownClassInstance) {
ICPPUnknownClassInstance ucli= (ICPPUnknownClassInstance) unknown;
final ICPPTemplateArgument[] arguments = ucli.getArguments();
ICPPTemplateArgument[] newArgs = CPPTemplates.instantiateArguments(arguments, tpMap, packOffset, within);
if (!t.equals(owner) && newArgs != arguments) {
newArgs= SemanticUtil.getSimplifiedArguments(newArgs);
result= new CPPUnknownClassInstance((ICPPUnknownBinding) t, ucli.getNameCharArray(), newArgs);
}
} else if (!t.equals(owner)) {
if (unknown instanceof ICPPUnknownClassType) {
result= new CPPUnknownClass((ICPPUnknownBinding)t, unknown.getNameCharArray());
} else if (unknown instanceof IFunction) {
result= new CPPUnknownClass((ICPPUnknownBinding)t, unknown.getNameCharArray());
} else {
result= new CPPUnknownBinding((ICPPUnknownBinding) t, unknown.getNameCharArray());
}
}
} else if (t instanceof ICPPClassType) {
IScope s = ((ICPPClassType) t).getCompositeScope();
if (s != null) {
result= CPPSemantics.resolveUnknownName(s, unknown);
if (unknown instanceof ICPPUnknownClassInstance && result instanceof ICPPTemplateDefinition) {
ICPPTemplateArgument[] newArgs = CPPTemplates.instantiateArguments(
((ICPPUnknownClassInstance) unknown).getArguments(), tpMap, packOffset, within);
if (result instanceof ICPPClassTemplate) {
result = instantiate((ICPPClassTemplate) result, newArgs);
}
}
}
}
}
return result;
}
private static IBinding resolveDeferredClassInstance(ICPPDeferredClassInstance dci,
ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) {
ICPPTemplateArgument[] arguments = dci.getTemplateArguments();
ICPPTemplateArgument[] newArgs;
try {
newArgs = CPPTemplates.instantiateArguments(arguments, tpMap, packOffset, within);
} catch (DOMException e) {
return e.getProblem();
}
boolean changed= arguments != newArgs;
ICPPClassTemplate classTemplate = dci.getClassTemplate();
IType classTemplateSpecialization= instantiateType(classTemplate, tpMap, packOffset, within);
if (classTemplateSpecialization != classTemplate && classTemplateSpecialization instanceof ICPPClassTemplate) {
classTemplate= (ICPPClassTemplate) classTemplateSpecialization;
changed= true;
}
if (changed) {
IBinding inst= instantiate(classTemplate, newArgs);
if (inst != null)
return inst;
}
return dci;
}
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);
}
public static ICPPTemplateParameterMap createParameterMap(ICPPTemplateDefinition tdef, ICPPTemplateArgument[] args) {
ICPPTemplateParameter[] tpars= tdef.getTemplateParameters();
int len= Math.min(tpars.length, args.length);
CPPTemplateParameterMap result= new CPPTemplateParameterMap(len);
for (int i = 0; i < len; i++) {
result.put(tpars[i], args[i]);
}
return result;
}
/**
* @deprecated for backwards compatibility, only.
*/
@Deprecated
public static IType[] getArguments(ICPPTemplateArgument[] arguments) {
IType[] types= new IType[arguments.length];
for (int i = 0; i < types.length; i++) {
final ICPPTemplateArgument arg= arguments[i];
if (arg == null) {
types[i]= null;
} else if (arg.isNonTypeValue()) {
types[i]= arg.getTypeOfNonTypeValue();
} else {
types[i]= arg.getTypeValue();
}
}
return types;
}
/**
* @deprecated for backwards compatibility, only.
*/
@Deprecated
public static ObjectMap getArgumentMap(IBinding b, ICPPTemplateParameterMap tpmap) {
// backwards compatibility
Integer[] keys= tpmap.getAllParameterPositions();
if (keys.length == 0)
return ObjectMap.EMPTY_MAP;
List<ICPPTemplateDefinition> defs= new ArrayList<ICPPTemplateDefinition>();
IBinding owner= b;
while (owner != null) {
if (owner instanceof ICPPTemplateDefinition) {
defs.add((ICPPTemplateDefinition) owner);
} else if (owner instanceof ICPPTemplateInstance) {
defs.add(((ICPPTemplateInstance) owner).getTemplateDefinition());
}
owner= owner.getOwner();
}
Collections.reverse(defs);
ObjectMap result= new ObjectMap(keys.length);
for (int key: keys) {
int nestingLevel= key >> 16;
int numParam= key & 0xffff;
if (0 <= numParam && 0 <= nestingLevel && nestingLevel < defs.size()) {
ICPPTemplateDefinition tdef= defs.get(nestingLevel);
ICPPTemplateParameter[] tps= tdef.getTemplateParameters();
if (numParam < tps.length) {
ICPPTemplateArgument arg= tpmap.getArgument(key);
if (arg != null) {
IType type= arg.isNonTypeValue() ? arg.getTypeOfNonTypeValue() : arg.getTypeValue();
result.put(tps[numParam], type);
}
}
}
}
return result;
}
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;
}
}