blob: f76d3471ef07c989e91eee580af153282cdff574 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2016 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)
* Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
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.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.DependentValue;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredVariableInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalEnumerator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
import org.eclipse.core.runtime.CoreException;
public class EvalID extends CPPDependentEvaluation {
private final ICPPEvaluation fFieldOwner;
private final char[] fName;
private final IBinding fNameOwner;
private final boolean fAddressOf;
private final boolean fQualified;
private final boolean fIsPointerDeref;
private final ICPPTemplateArgument[] fTemplateArgs;
public EvalID(ICPPEvaluation fieldOwner, IBinding nameOwner, char[] simpleID, boolean addressOf,
boolean qualified, boolean isPointerDeref, ICPPTemplateArgument[] templateArgs,
IASTNode pointOfDefinition) {
this(fieldOwner, nameOwner, simpleID, addressOf, qualified, isPointerDeref, templateArgs,
findEnclosingTemplate(pointOfDefinition));
}
public EvalID(ICPPEvaluation fieldOwner, IBinding nameOwner, char[] simpleID, boolean addressOf,
boolean qualified, boolean isPointerDeref, ICPPTemplateArgument[] templateArgs,
IBinding templateDefinition) {
super(templateDefinition);
if (simpleID == null)
throw new NullPointerException("simpleID"); //$NON-NLS-1$
fFieldOwner= fieldOwner;
fName= simpleID;
fNameOwner= nameOwner;
fAddressOf= addressOf;
fQualified= qualified;
fIsPointerDeref= isPointerDeref;
fTemplateArgs= templateArgs;
}
/**
* Returns the field owner expression, or {@code null}.
*/
public ICPPEvaluation getFieldOwner() {
return fFieldOwner;
}
public IBinding getNameOwner() {
return fNameOwner;
}
public char[] getName() {
return fName;
}
public boolean isAddressOf() {
return fAddressOf;
}
public boolean isQualified() {
return fQualified;
}
public boolean isPointerDeref() {
return fIsPointerDeref;
}
/**
* Returns the template arguments, or {@code null} if there are no template arguments.
*/
public ICPPTemplateArgument[] getTemplateArgs() {
return fTemplateArgs;
}
@Override
public boolean isInitializerList() {
return false;
}
@Override
public boolean isFunctionSet() {
return false;
}
@Override
public boolean isTypeDependent() {
return true;
}
@Override
public boolean isValueDependent() {
return true;
}
@Override
public boolean isConstantExpression(IASTNode point) {
return false;
}
@Override
public IType getType(IASTNode point) {
return new TypeOfDependentExpression(this);
}
@Override
public IValue getValue(IASTNode point) {
// Name lookup is not needed here because it was already done in the "instantiate" method.
return DependentValue.create(this);
}
@Override
public ValueCategory getValueCategory(IASTNode point) {
return PRVALUE;
}
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
short firstBytes = ITypeMarshalBuffer.EVAL_ID;
if (fAddressOf)
firstBytes |= ITypeMarshalBuffer.FLAG1;
if (fQualified)
firstBytes |= ITypeMarshalBuffer.FLAG2;
if (fTemplateArgs != null)
firstBytes |= ITypeMarshalBuffer.FLAG3;
if (fIsPointerDeref)
firstBytes |= ITypeMarshalBuffer.FLAG4;
buffer.putShort(firstBytes);
buffer.marshalEvaluation(fFieldOwner, false);
buffer.putCharArray(fName);
buffer.marshalBinding(fNameOwner);
if (fTemplateArgs != null) {
buffer.putInt(fTemplateArgs.length);
for (ICPPTemplateArgument arg : fTemplateArgs) {
buffer.marshalTemplateArgument(arg);
}
}
marshalTemplateDefinition(buffer);
}
public static ICPPEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
final boolean addressOf= (firstBytes & ITypeMarshalBuffer.FLAG1) != 0;
final boolean qualified= (firstBytes & ITypeMarshalBuffer.FLAG2) != 0;
final boolean isPointerDeref= (firstBytes & ITypeMarshalBuffer.FLAG4) != 0;
ICPPEvaluation fieldOwner= buffer.unmarshalEvaluation();
char[] name= buffer.getCharArray();
IBinding nameOwner= buffer.unmarshalBinding();
ICPPTemplateArgument[] args= null;
if ((firstBytes & ITypeMarshalBuffer.FLAG3) != 0) {
int len= buffer.getInt();
args = new ICPPTemplateArgument[len];
for (int i = 0; i < args.length; i++) {
args[i]= buffer.unmarshalTemplateArgument();
}
}
IBinding templateDefinition= buffer.unmarshalBinding();
return new EvalID(fieldOwner, nameOwner, name, addressOf, qualified, isPointerDeref, args,
templateDefinition);
}
public static ICPPEvaluation create(IASTIdExpression expr) {
final IASTName name = expr.getName();
IBinding binding = name.resolvePreBinding();
boolean qualified = name instanceof ICPPASTQualifiedName;
if (binding instanceof IProblemBinding || binding instanceof IType || binding instanceof ICPPConstructor)
return EvalFixed.INCOMPLETE;
if (binding instanceof CPPFunctionSet) {
return new EvalFunctionSet((CPPFunctionSet) binding, qualified, isAddressOf(expr), null, expr);
}
if (binding instanceof ICPPUnknownBinding) {
// If the id-expression names a variable template, there is no need to defer name lookup.
if (binding instanceof ICPPDeferredVariableInstance) {
return new EvalBinding(binding, null, expr);
}
ICPPTemplateArgument[] templateArgs = null;
final IASTName lastName = name.getLastName();
if (lastName instanceof ICPPASTTemplateId) {
try {
templateArgs= CPPTemplates.createTemplateArgumentArray((ICPPASTTemplateId) lastName);
} catch (DOMException e) {
return EvalFixed.INCOMPLETE;
}
}
if (binding instanceof CPPDeferredFunction) {
ICPPFunction[] candidates = ((CPPDeferredFunction) binding).getCandidates();
if (candidates != null) {
CPPFunctionSet functionSet = new CPPFunctionSet(candidates, templateArgs, null);
return new EvalFunctionSet(functionSet, qualified, isAddressOf(expr), null, expr);
} else {
// Just store the name. ADL at the time of instantiation might come up with bindings.
return new EvalFunctionSet(name.getSimpleID(), qualified, isAddressOf(expr), expr);
}
}
IBinding owner = binding.getOwner();
if (owner instanceof IProblemBinding)
return EvalFixed.INCOMPLETE;
ICPPEvaluation fieldOwner= null;
IType fieldOwnerType= withinNonStaticMethod(expr);
if (fieldOwnerType != null) {
fieldOwner= new EvalFixed(fieldOwnerType, ValueCategory.LVALUE, IntegralValue.UNKNOWN);
}
return new EvalID(fieldOwner, owner, name.getSimpleID(), isAddressOf(expr),
name instanceof ICPPASTQualifiedName, false, templateArgs, expr);
}
/**
* 9.3.1-3 Transformation to class member access within a non-static member function.
*/
if (binding instanceof ICPPMember && !(binding instanceof IType)
&& !(binding instanceof ICPPConstructor) &&!((ICPPMember) binding).isStatic()) {
IType fieldOwnerType= withinNonStaticMethod(expr);
if (fieldOwnerType != null) {
return new EvalMemberAccess(fieldOwnerType, LVALUE, binding, true, expr);
}
}
if (binding instanceof IEnumerator) {
IType type= ((IEnumerator) binding).getType();
if (type instanceof ICPPEnumeration) {
ICPPEnumeration enumType= (ICPPEnumeration) type;
// [dcl.enum] 7.2-5
if (isInsideEnum(expr, enumType)) {
if (binding instanceof ICPPInternalEnumerator) {
type = enumType.getFixedType();
if (type == null) {
type = ((ICPPInternalEnumerator) binding).getInternalType();
}
}
return new EvalBinding(binding, type, expr);
}
}
return new EvalBinding(binding, null, expr);
}
if (binding instanceof ICPPTemplateNonTypeParameter || binding instanceof IVariable
|| binding instanceof IFunction) {
return new EvalBinding(binding, null, expr);
}
return EvalFixed.INCOMPLETE;
}
/**
* Returns {@code true} if the given node is located inside the given enum.
*/
private static boolean isInsideEnum(IASTNode node, ICPPEnumeration enumBinding) {
IASTEnumerator enumeratorNode = ASTQueries.findAncestorWithType(node, IASTEnumerator.class);
if (enumeratorNode == null)
return false;
IBinding enumerator = enumeratorNode.getName().getBinding();
return enumerator != null && enumBinding == enumerator.getOwner();
}
private static IType withinNonStaticMethod(IASTExpression expr) {
IASTNode parent= expr.getParent();
while (parent != null && !(parent instanceof ICPPASTFunctionDefinition)) {
parent= parent.getParent();
}
if (parent instanceof ICPPASTFunctionDefinition) {
ICPPASTFunctionDefinition fdef= (ICPPASTFunctionDefinition) parent;
// Resolution of the method name triggers name resolution inside the
// decl-specifier of the method definition. If we are currently
// resolving something inside the decl-specifier, this can lead to
// recursion.
if (ASTQueries.isAncestorOf(fdef.getDeclSpecifier(), expr)) {
return null;
}
final IBinding methodBinding = fdef.getDeclarator().getName().resolvePreBinding();
if (methodBinding instanceof ICPPMethod && !((ICPPMethod) methodBinding).isStatic()) {
IScope scope = CPPVisitor.getContainingScope(expr);
return CPPVisitor.getImpliedObjectType(scope);
}
}
return null;
}
private static boolean isAddressOf(IASTIdExpression expr) {
IASTNode e = expr.getParent();
while (e instanceof IASTUnaryExpression) {
final IASTUnaryExpression unary = (IASTUnaryExpression) e;
final int op= unary.getOperator();
if (op == IASTUnaryExpression.op_bracketedPrimary) {
e= unary.getOperand();
} else {
return op == IASTUnaryExpression.op_amper;
}
}
return false;
}
@Override
public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) {
ICPPTemplateArgument[] templateArgs = fTemplateArgs;
if (templateArgs != null) {
templateArgs = instantiateArguments(templateArgs, context, false);
}
char[] name = fName;
name = CPPTemplates.instantiateName(name, context, getTemplateDefinition());
ICPPEvaluation fieldOwner = fFieldOwner;
if (fieldOwner != null) {
fieldOwner = fieldOwner.instantiate(context, maxDepth);
}
IBinding nameOwner = fNameOwner;
if (nameOwner instanceof ICPPClassTemplate) {
ICPPDeferredClassInstance deferred = CPPTemplates.createDeferredInstance((ICPPClassTemplate) nameOwner);
nameOwner = resolveUnknown(deferred, context);
} else if (nameOwner instanceof IType) {
IType type = CPPTemplates.instantiateType((IType) nameOwner, context);
type = getNestedType(type, TDEF | REF | CVTYPE);
if (!(type instanceof IBinding))
return EvalFixed.INCOMPLETE;
nameOwner = (IBinding) type;
}
if (fieldOwner instanceof IProblemBinding || nameOwner instanceof IProblemBinding)
return EvalFixed.INCOMPLETE;
if (templateArgs == fTemplateArgs && fieldOwner == fFieldOwner && nameOwner == fNameOwner)
return this;
boolean nameOwnerStillDependent = false;
if (nameOwner instanceof ICPPClassType) {
ICPPEvaluation eval = resolveName(name, (ICPPClassType) nameOwner, null, templateArgs, null, context.getPoint());
if (eval != null)
return eval;
if (CPPTemplates.isDependentType((ICPPClassType) nameOwner)) {
nameOwnerStillDependent = true;
} else {
return EvalFixed.INCOMPLETE;
}
}
if (!nameOwnerStillDependent && fieldOwner != null && !fieldOwner.isTypeDependent()) {
IType fieldOwnerType = fieldOwner.getType(context.getPoint());
if (fIsPointerDeref) {
fieldOwnerType = SemanticUtil.getSimplifiedType(fieldOwnerType);
if (fieldOwnerType instanceof IPointerType) {
fieldOwnerType = ((IPointerType) fieldOwnerType).getType();
} else {
return EvalFixed.INCOMPLETE;
}
}
IType fieldOwnerClassTypeCV = SemanticUtil.getNestedType(fieldOwnerType, TDEF | REF);
IType fieldOwnerClassType = SemanticUtil.getNestedType(fieldOwnerClassTypeCV, CVTYPE);
if (fieldOwnerClassType instanceof ICPPClassType) {
ICPPEvaluation eval = resolveName(name, (ICPPClassType) fieldOwnerClassType, fieldOwner,
templateArgs, fieldOwnerClassTypeCV, context.getPoint());
if (eval != null)
return eval;
if (!CPPTemplates.isDependentType(fieldOwnerClassType))
return EvalFixed.INCOMPLETE;
}
}
return new EvalID(fieldOwner, nameOwner, name, fAddressOf, fQualified, fIsPointerDeref, templateArgs,
getTemplateDefinition());
}
@Override
public ICPPEvaluation computeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) {
if (fFieldOwner == null) {
return this;
}
ICPPEvaluation fieldOwner = fFieldOwner.computeForFunctionCall(record, context.recordStep());
if (fieldOwner == fFieldOwner) {
return this;
}
EvalID newEvalID = new EvalID(fieldOwner, fNameOwner, fName, fAddressOf, fQualified, fIsPointerDeref, fTemplateArgs, getTemplateDefinition());
return newEvalID;
}
private ICPPEvaluation resolveName(char[] name, ICPPClassType nameOwner, ICPPEvaluation ownerEval,
ICPPTemplateArgument[] templateArgs, IType impliedObjectType, IASTNode point) {
LookupData data = new LookupData(name, templateArgs, point);
data.qualified = fQualified;
try {
CPPSemantics.lookup(data, nameOwner.getCompositeScope());
} catch (DOMException e) {
}
IBinding[] bindings = data.getFoundBindings();
if (bindings.length != 0) {
IBinding binding = bindings[0];
if (binding instanceof ICPPFunction) {
ICPPFunction[] functions = new ICPPFunction[bindings.length];
System.arraycopy(bindings, 0, functions, 0, bindings.length);
return new EvalFunctionSet(new CPPFunctionSet(functions, templateArgs, null), fQualified,
fAddressOf, impliedObjectType, getTemplateDefinition());
}
if (binding instanceof CPPFunctionSet) {
return new EvalFunctionSet((CPPFunctionSet) binding, fQualified, fAddressOf,
impliedObjectType, getTemplateDefinition());
}
if (binding instanceof IEnumerator) {
return new EvalBinding(binding, null, getTemplateDefinition());
}
if (binding instanceof ICPPMember) {
if (((ICPPMember) binding).isStatic()) {
// Don't use EvalMemberAccess to represent accesses of static members.
return new EvalBinding(binding, null, getTemplateDefinition());
}
if (ownerEval != null) {
return new EvalMemberAccess(nameOwner, ownerEval.getValueCategory(point), binding, ownerEval, false, point);
} else {
return new EvalMemberAccess(nameOwner, ValueCategory.PRVALUE, binding, false, getTemplateDefinition());
}
}
}
return null;
}
@Override
public int determinePackSize(ICPPTemplateParameterMap tpMap) {
int r = fFieldOwner != null ? fFieldOwner.determinePackSize(tpMap) : CPPTemplates.PACK_SIZE_NOT_FOUND;
if (fNameOwner instanceof ICPPUnknownBinding) {
r = CPPTemplates.combinePackSize(r, CPPTemplates.determinePackSize((ICPPUnknownBinding) fNameOwner, tpMap));
}
if (fTemplateArgs != null) {
for (ICPPTemplateArgument arg : fTemplateArgs) {
r = CPPTemplates.combinePackSize(r, CPPTemplates.determinePackSize(arg, tpMap));
}
}
return r;
}
@Override
public boolean referencesTemplateParameter() {
return fFieldOwner != null && fFieldOwner.referencesTemplateParameter();
}
}