blob: 1b82b23890c9ae1c9c4c143eac27d8b4565bfd01 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2014 Wind River Systems, Inc. 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:
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromReturnType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromReturnType;
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.TDEF;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
import org.eclipse.cdt.internal.core.dom.parser.DependentValue;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper.MethodKind;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
import org.eclipse.core.runtime.CoreException;
/**
* Performs evaluation of an expression.
*/
public class EvalTypeId extends CPPDependentEvaluation {
public static final ICPPFunction AGGREGATE_INITIALIZATION = new CPPFunction(null) {
@Override
public String toString() {
return "AGGREGATE_INITIALIZATION"; //$NON-NLS-1$
}
};
private final IType fInputType;
private final ICPPEvaluation[] fArguments;
private final boolean fRepresentsNewExpression;
private boolean fUsesBracedInitList; // Whether the constructor call uses { ... } instead of (...).
private IType fOutputType;
private ICPPFunction fConstructor = CPPFunction.UNINITIALIZED_FUNCTION;
private boolean fCheckedIsTypeDependent;
private boolean fIsTypeDependent;
private boolean fCheckedIsConstantExpression;
private boolean fIsConstantExpression;
public EvalTypeId(IType type, IASTNode pointOfDefinition, boolean usesBracedInitList,
ICPPEvaluation... arguments) {
this(type, findEnclosingTemplate(pointOfDefinition), false, usesBracedInitList, arguments);
}
public EvalTypeId(IType type, IBinding templateDefinition, boolean forNewExpression,
boolean usesBracedInitList, ICPPEvaluation... arguments) {
super(templateDefinition);
if (arguments == null)
throw new NullPointerException("arguments"); //$NON-NLS-1$
if (!CPPTemplates.isDependentType(type))
type = SemanticUtil.getNestedType(type, TDEF);
fInputType= type;
fArguments= arguments;
fRepresentsNewExpression = forNewExpression;
fUsesBracedInitList = usesBracedInitList;
}
public static EvalTypeId createForNewExpression(IType type, IASTNode pointOfDefinition,
boolean usesBracedInitList, ICPPEvaluation... arguments) {
return new EvalTypeId(type, findEnclosingTemplate(pointOfDefinition), true, usesBracedInitList,
arguments);
}
public IType getInputType() {
return fInputType;
}
public ICPPEvaluation[] getArguments() {
return fArguments;
}
public boolean representsNewExpression() {
return fRepresentsNewExpression;
}
public boolean usesBracedInitList() {
return fUsesBracedInitList;
}
@Override
public boolean isInitializerList() {
return false;
}
@Override
public boolean isFunctionSet() {
return false;
}
@Override
public IType getType() {
if (fOutputType == null) {
fOutputType= computeType();
}
return fOutputType;
}
private IType computeType() {
if (isTypeDependent())
return new TypeOfDependentExpression(this);
IType type = typeFromReturnType(fInputType);
if (fRepresentsNewExpression)
return new CPPPointerType(type);
return type;
}
@Override
public IValue getValue() {
if (isValueDependent())
return DependentValue.create(this);
if (isTypeDependent())
return DependentValue.create(this);
if (fRepresentsNewExpression)
return IntegralValue.UNKNOWN;
IType inputType = SemanticUtil.getNestedType(fInputType, CVTYPE);
if (inputType instanceof ICPPClassType) {
ICPPClassType classType = (ICPPClassType) inputType;
IBinding ctor = getConstructor();
if (EvalUtil.isCompilerGeneratedCtor(ctor)) {
return CompositeValue.create(classType);
} else if (ctor == AGGREGATE_INITIALIZATION) {
return CompositeValue.create(new EvalInitList(fArguments, getTemplateDefinition()),
classType);
} else if (ctor != null) {
EvalConstructor evalCtor = new EvalConstructor(classType, (ICPPConstructor) ctor,
fArguments, getTemplateDefinition());
ICPPEvaluation computedEvalCtor = evalCtor.computeForFunctionCall(new ActivationRecord(), new ConstexprEvaluationContext());
return computedEvalCtor.getValue();
} else {
return IntegralValue.ERROR;
}
}
if (fArguments.length == 0 || isEmptyInitializerList(fArguments)) {
if (inputType instanceof ICPPBasicType) {
switch (((ICPPBasicType) inputType).getKind()) {
case eInt:
case eInt128:
case eDouble:
case eBoolean:
case eFloat:
case eFloat128:
case eNullPtr:
case eChar:
case eChar16:
case eChar32:
case eWChar:
return IntegralValue.create(0l);
case eUnspecified:
case eVoid:
default:
return IntegralValue.UNKNOWN;
}
}
}
if (fArguments.length == 1) {
return fArguments[0].getValue();
}
return IntegralValue.UNKNOWN;
}
private boolean isEmptyInitializerList(ICPPEvaluation[] arguments) {
return arguments.length == 1 && arguments[0] instanceof EvalInitList && ((EvalInitList) arguments[0]).getClauses().length == 0;
}
@Override
public boolean isTypeDependent() {
if (!fCheckedIsTypeDependent) {
fCheckedIsTypeDependent = true;
fIsTypeDependent = CPPTemplates.isDependentType(fInputType) || containsDependentType(fArguments);
}
return fIsTypeDependent;
}
@Override
public boolean isValueDependent() {
if (CPPTemplates.isDependentType(fInputType))
return true;
for (ICPPEvaluation arg : fArguments) {
if (arg.isValueDependent())
return true;
}
return false;
}
@Override
public boolean isConstantExpression() {
if (!fCheckedIsConstantExpression) {
fCheckedIsConstantExpression = true;
fIsConstantExpression = computeIsConstantExpression();
}
return fIsConstantExpression;
}
private boolean computeIsConstantExpression() {
return !fRepresentsNewExpression
&& areAllConstantExpressions(fArguments)
&& isNullOrConstexprFunc(getConstructor());
}
@Override
public boolean isEquivalentTo(ICPPEvaluation other) {
if (!(other instanceof EvalTypeId)) {
return false;
}
EvalTypeId o = (EvalTypeId) other;
return fInputType.isSameType(o.fInputType)
&& areEquivalentEvaluations(fArguments, o.fArguments)
&& fRepresentsNewExpression == o.fRepresentsNewExpression
&& fUsesBracedInitList == o.fUsesBracedInitList;
}
@Override
public ValueCategory getValueCategory() {
return valueCategoryFromReturnType(fInputType);
}
public ICPPFunction getConstructor() {
if (fConstructor == CPPFunction.UNINITIALIZED_FUNCTION) {
fConstructor = computeConstructor();
}
return fConstructor;
}
private static boolean allConstructorsAreCompilerGenerated(ICPPConstructor[] constructors) {
for (ICPPConstructor constructor : constructors) {
if (!EvalUtil.isCompilerGeneratedCtor(constructor))
return false;
}
return true;
}
private ICPPFunction computeConstructor() {
if (isTypeDependent())
return null;
IType simplifiedType = SemanticUtil.getNestedType(fInputType, TDEF | CVTYPE);
if (simplifiedType instanceof ICPPClassType) {
ICPPClassType classType = (ICPPClassType) simplifiedType;
ICPPEvaluation[] arguments = fArguments;
ICPPConstructor[] constructors = classType.getConstructors();
if (arguments.length == 1 && arguments[0] instanceof EvalInitList) {
// List-initialization of a class (dcl.init.list-3).
if (TypeTraits.isAggregateClass(classType)) {
// Pretend that aggregate initialization is calling the default constructor.
return findDefaultConstructor(classType, constructors);
}
if (((EvalInitList) arguments[0]).getClauses().length == 0) {
ICPPMethod ctor = findDefaultConstructor(classType, constructors);
if (ctor != null)
return ctor;
}
ICPPConstructor[] ctors = getInitializerListConstructors(constructors);
if (ctors.length != 0) {
constructors = ctors;
} else {
arguments = ((EvalInitList) arguments[0]).getClauses();
}
}
LookupData data = new LookupData(classType.getNameCharArray(), null,
CPPSemantics.getCurrentLookupPoint());
data.foundItems = constructors;
data.setFunctionArguments(false, arguments);
try {
IBinding binding = CPPSemantics.resolveFunction(data, constructors, true, false);
if (binding instanceof ICPPFunction) {
return (ICPPFunction) binding;
}
} catch (DOMException e) {
CCorePlugin.log(e);
}
if (fUsesBracedInitList && allConstructorsAreCompilerGenerated(constructors)) {
return AGGREGATE_INITIALIZATION;
}
}
return null;
}
private ICPPConstructor findDefaultConstructor(ICPPClassType classType, ICPPConstructor[] constructors) {
for (ICPPConstructor ctor : constructors) {
if (ctor.isImplicit() && ClassTypeHelper.getMethodKind(classType, ctor) == MethodKind.DEFAULT_CTOR)
return ctor;
}
return null;
}
/**
* Returns constructors that can be called by passing a single {@code std::initializer_list}
* as an argument.
*/
private ICPPConstructor[] getInitializerListConstructors(ICPPConstructor[] constructors) {
ICPPConstructor[] result = ICPPConstructor.EMPTY_CONSTRUCTOR_ARRAY;
ICPPClassTemplate template = CPPVisitor.get_initializer_list();
if (template == null)
return result;
for (ICPPConstructor ctor : constructors) {
if (ctor.getRequiredArgumentCount() <= 1) {
IType[] parameterTypes = ctor.getType().getParameterTypes();
if (parameterTypes.length != 0) {
IType type = parameterTypes[0];
if (type instanceof ICPPSpecialization) {
IBinding specialized = ((ICPPSpecialization) type).getSpecializedBinding();
if (specialized instanceof ICPPClassTemplate
&& template.isSameType((IType) specialized)) {
result = ArrayUtil.append(result, ctor);
}
}
}
}
}
return ArrayUtil.trim(result);
}
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
short firstBytes = ITypeMarshalBuffer.EVAL_TYPE_ID;
if (fRepresentsNewExpression)
firstBytes |= ITypeMarshalBuffer.FLAG1;
if (fUsesBracedInitList)
firstBytes |= ITypeMarshalBuffer.FLAG2;
buffer.putShort(firstBytes);
buffer.marshalType(fInputType);
buffer.putInt(fArguments.length);
for (ICPPEvaluation arg : fArguments) {
buffer.marshalEvaluation(arg, includeValue);
}
marshalTemplateDefinition(buffer);
}
public static ICPPEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer)
throws CoreException {
IType type= buffer.unmarshalType();
ICPPEvaluation[] args= null;
int len= buffer.getInt();
args = new ICPPEvaluation[len];
for (int i = 0; i < args.length; i++) {
args[i]= buffer.unmarshalEvaluation();
}
IBinding templateDefinition= buffer.unmarshalBinding();
boolean forNewExpression = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0;
boolean usesBracedInitList = (firstBytes & ITypeMarshalBuffer.FLAG2) != 0;
EvalTypeId result = new EvalTypeId(type, templateDefinition, forNewExpression, usesBracedInitList,
args);
return result;
}
@Override
public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) {
ICPPEvaluation[] args= instantiateCommaSeparatedSubexpressions(fArguments, context, maxDepth);
IType type = CPPTemplates.instantiateType(fInputType, context);
if (args == fArguments && type == fInputType)
return this;
EvalTypeId result = new EvalTypeId(type, getTemplateDefinition(), fRepresentsNewExpression,
fUsesBracedInitList, args);
if (!result.isTypeDependent()) {
IType simplifiedType = SemanticUtil.getNestedType(type, SemanticUtil.TDEF);
if (simplifiedType instanceof ICPPClassType) {
// Check the constructor call and return EvalFixed.INCOMPLETE to indicate a substitution
// failure if the call cannot be resolved.
ICPPFunction constructor = result.getConstructor();
if (constructor == null || constructor instanceof IProblemBinding || constructor.isDeleted()) {
return EvalFixed.INCOMPLETE;
}
}
}
return result;
}
@Override
public ICPPEvaluation computeForFunctionCall(ActivationRecord record,
ConstexprEvaluationContext context) {
ICPPFunction constructor = getConstructor();
if (constructor != null && constructor instanceof ICPPConstructor) {
return new EvalConstructor(fInputType, (ICPPConstructor) constructor, fArguments,
getTemplateDefinition()).computeForFunctionCall(record, context);
}
ICPPEvaluation[] args = fArguments;
for (int i = 0; i < fArguments.length; i++) {
ICPPEvaluation arg = fArguments[i].computeForFunctionCall(record, context.recordStep());
if (arg != fArguments[i]) {
if (args == fArguments) {
args = new ICPPEvaluation[fArguments.length];
System.arraycopy(fArguments, 0, args, 0, fArguments.length);
}
args[i] = arg;
}
}
if (args == fArguments) {
return this;
}
EvalTypeId evalTypeId = new EvalTypeId(fInputType, getTemplateDefinition(), fRepresentsNewExpression,
fUsesBracedInitList, args);
return evalTypeId;
}
@Override
public int determinePackSize(ICPPTemplateParameterMap tpMap) {
int r = CPPTemplates.determinePackSize(fInputType, tpMap);
for (ICPPEvaluation arg : fArguments) {
r = CPPTemplates.combinePackSize(r, arg.determinePackSize(tpMap));
}
return r;
}
@Override
public boolean referencesTemplateParameter() {
for (ICPPEvaluation arg : fArguments) {
if (arg.referencesTemplateParameter())
return true;
}
return false;
}
}