blob: dcddf9ac317128c69999c74b551ba1f19494ecbb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IQualifierType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation.ConstexprEvaluationContext;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
import org.eclipse.core.runtime.CoreException;
public final class ExecDeclarator implements ICPPExecution {
private final ICPPBinding declaredBinding;
private final ICPPEvaluation initializerEval;
public ExecDeclarator(ICPPBinding declaredBinding, ICPPEvaluation initializerEval) {
this.declaredBinding = declaredBinding;
this.initializerEval = initializerEval;
}
@Override
public ICPPExecution executeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) {
if (!(declaredBinding instanceof ICPPVariable))
return this;
ICPPVariable declaredVariable = (ICPPVariable) declaredBinding;
IType type = declaredVariable.getType();
ICPPEvaluation initialValue = createInitialValue(type, record, context);
if (initialValue == null || initialValue == EvalFixed.INCOMPLETE)
return ExecIncomplete.INSTANCE;
record.update(declaredBinding, initialValue);
return this;
}
public ICPPBinding getDeclaredBinding() {
return declaredBinding;
}
private static ICPPEvaluation maybeUnwrapInitList(ICPPEvaluation eval, IType targetType) {
// Only 1-element initializer lists are eligible for unwrapping.
if (!(eval instanceof EvalInitList))
return eval;
EvalInitList initList = (EvalInitList) eval;
ICPPEvaluation[] clauses = initList.getClauses();
if (clauses.length != 1)
return eval;
// Never unwrap initializers for array types.
if (targetType instanceof IArrayType)
return eval;
// Only unwrap initializers for class types if the type of the initializer
// element matches the class type, indicating that we're calling the
// implicit copy constructor (as opposed to doing memberwise initialization).
ICPPEvaluation clause = clauses[0];
if (targetType instanceof ICPPClassType && !clause.getType().isSameType(targetType))
return eval;
// Otherwise unwrap.
return clause;
}
private ICPPEvaluation createInitialValue(IType type, ActivationRecord record,
ConstexprEvaluationContext context) {
if (initializerEval == null)
return createDefaultInitializedCompositeValue(type);
IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE);
ICPPEvaluation computedInitializerEval =
initializerEval.computeForFunctionCall(record, context.recordStep());
// In some contexts, unwrap 1-element initializer lists.
computedInitializerEval = maybeUnwrapInitList(computedInitializerEval, nestedType);
if (type instanceof ICPPReferenceType)
return createReferenceValue(record, context, computedInitializerEval);
if (nestedType instanceof IPointerType && !isCStringType(nestedType))
return createPointerValue(record, context, computedInitializerEval);
if (nestedType instanceof IArrayType && !isCStringType(nestedType)) {
if (computedInitializerEval instanceof EvalInitList) {
IValue value = CompositeValue.create((EvalInitList) computedInitializerEval,
(IArrayType) nestedType);
return new EvalFixed(type, computedInitializerEval.getValueCategory(), value);
}
// TODO(sprigogin): Should something else be done here?
return EvalFixed.INCOMPLETE;
}
if (isValueInitialization(computedInitializerEval)) {
ICPPEvaluation defaultValue =
new EvalTypeId(type, computedInitializerEval.getTemplateDefinition(), false, false,
ICPPEvaluation.EMPTY_ARRAY);
return new EvalFixed(type, defaultValue.getValueCategory(), defaultValue.getValue());
}
return new EvalFixed(type, computedInitializerEval.getValueCategory(),
computedInitializerEval.getValue());
}
private static ICPPEvaluation createDefaultInitializedCompositeValue(IType type) {
if (!(type instanceof ICPPClassType)) {
return EvalFixed.INCOMPLETE;
}
ICPPClassType classType = (ICPPClassType) type;
// TODO(nathanridge): CompositeValue.create() only consider default member initializers, not
// constructors. Should we be considering constructors here as well?
IValue compositeValue = CompositeValue.create(classType);
EvalFixed initialValue = new EvalFixed(type, ValueCategory.PRVALUE, compositeValue);
return initialValue;
}
private ICPPEvaluation createReferenceValue(ActivationRecord record, ConstexprEvaluationContext context,
ICPPEvaluation computedInitializerEval) {
ICPPEvaluation initValue = initializerEval;
if (initValue instanceof EvalInitList) {
initValue = ((EvalInitList) initValue).getClauses()[0];
} else if (!(initValue instanceof EvalBinding)) {
initValue = initializerEval.getValue().getSubValue(0);
}
IBinding templateDefinition = initializerEval.getTemplateDefinition();
if (initValue instanceof EvalBinding)
return createReferenceFromBinding(record, templateDefinition, (EvalBinding) initValue);
if (initValue instanceof EvalBinary && computedInitializerEval instanceof EvalCompositeAccess)
return createReferenceFromCompositeAccess(record, templateDefinition,
(EvalCompositeAccess) computedInitializerEval);
return EvalFixed.INCOMPLETE;
}
private ICPPEvaluation createPointerValue(ActivationRecord record, ConstexprEvaluationContext context,
ICPPEvaluation computedInitializerEval) {
ICPPEvaluation initValue = initializerEval.getValue().getSubValue(0);
if (isPointerToArray(initValue)) {
EvalCompositeAccess arrayPointer = new EvalCompositeAccess(computedInitializerEval, 0);
return createPointerFromCompositeAccess(record, initializerEval.getTemplateDefinition(), arrayPointer);
}
if (computedInitializerEval instanceof EvalPointer)
return ((EvalPointer) computedInitializerEval).copy();
return EvalFixed.INCOMPLETE;
}
private static boolean isValueInitialization(ICPPEvaluation eval) {
if (eval instanceof EvalInitList) {
EvalInitList evalInitList = (EvalInitList) eval;
return evalInitList.getClauses().length == 0;
}
return false;
}
private static boolean isPointerToArray(ICPPEvaluation eval) {
return eval.getType() instanceof IArrayType;
}
private static ICPPEvaluation createReferenceFromBinding(ActivationRecord record,
IBinding templateDefinition, EvalBinding evalBinding) {
return new EvalReference(record, evalBinding.getBinding(), templateDefinition);
}
private static ICPPEvaluation createReferenceFromCompositeAccess(ActivationRecord record,
IBinding templateDefinition, EvalCompositeAccess evalCompAccess) {
return new EvalReference(record, evalCompAccess, templateDefinition);
}
private static ICPPEvaluation createPointerFromCompositeAccess(ActivationRecord record,
IBinding templateDefinition, EvalCompositeAccess evalCompAccess) {
return new EvalPointer(record, evalCompAccess, templateDefinition);
}
private static boolean isCStringType(IType type) {
IType nestedType = null;
if (type instanceof IArrayType) {
nestedType = ((IArrayType) type).getType();
} else if (type instanceof IPointerType) {
nestedType = ((IPointerType) type).getType();
}
if (nestedType instanceof IQualifierType) {
IQualifierType qualifierType = (IQualifierType) nestedType;
if (qualifierType.isConst() && !qualifierType.isVolatile())
return qualifierType.getType().isSameType(CPPBasicType.CHAR);
}
return false;
}
@Override
public ICPPExecution instantiate(InstantiationContext context, int maxDepth) {
ICPPBinding newDeclaredBinding;
if (declaredBinding instanceof ICPPVariable) {
ICPPVariable declaredVariable = (ICPPVariable) declaredBinding;
newDeclaredBinding = CPPTemplates.createVariableSpecialization(context, declaredVariable);
} else {
ICPPSpecialization owner = context.getContextSpecialization();
if (owner instanceof ICPPClassSpecialization) {
newDeclaredBinding = (ICPPBinding)
((ICPPClassSpecialization) owner).specializeMember(declaredBinding);
} else {
// TODO: Non-class owners should also have a specializeMember() function which
// implements a caching mechanism.
newDeclaredBinding = (ICPPBinding) CPPTemplates.createSpecialization(owner, declaredBinding);
}
}
ICPPEvaluation newInitializerEval =
initializerEval == null ? null : initializerEval.instantiate(context, maxDepth);
return new ExecDeclarator(newDeclaredBinding, newInitializerEval);
}
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
buffer.putShort(ITypeMarshalBuffer.EXEC_DECLARATOR);
buffer.marshalBinding(declaredBinding);
buffer.marshalEvaluation(initializerEval, includeValue);
}
public static ICPPExecution unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
ICPPBinding declaredBinding = (ICPPBinding) buffer.unmarshalBinding();
ICPPEvaluation initializerEval = buffer.unmarshalEvaluation();
return new ExecDeclarator(declaredBinding, initializerEval);
}
}