/******************************************************************************* * Copyright (c) 2012, 2015 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.core.dom.ast.IASTExpression.ValueCategory.LVALUE; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.XVALUE; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.glvalueType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.prvalueType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.prvalueTypeWithResolvedTypedefs; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromFunctionCall; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.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.getUltimateTypeUptoPointers; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IPointerType; 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.ICPPClassSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; 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.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; 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.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalUnknownScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics.LookupMode; import org.eclipse.core.runtime.CoreException; import java.util.Collection; public class EvalMemberAccess extends CPPDependentEvaluation { private final IType fOwnerType; private final IBinding fMember; private final ValueCategory fOwnerValueCategory; private final boolean fIsPointerDeref; // An EvalMemberAccess has an owner evaluation if it does not represent // a member access through the "this" pointer. If it does, the owner // evaluation is derived from the activation record (passed to // computeForFunctionCall()). private ICPPEvaluation fOwnerEval; private IType fType; private boolean fIsTypeDependent; private boolean fCheckedIsTypeDependent; private boolean fIsValueDependent; private boolean fCheckedIsValueDependent; public EvalMemberAccess(IType ownerType, ValueCategory ownerValueCat, IBinding member, boolean isPointerDeref, IASTNode pointOfDefinition) { this(ownerType, ownerValueCat, member, isPointerDeref, findEnclosingTemplate(pointOfDefinition)); } public EvalMemberAccess(IType ownerType, ValueCategory ownerValueCat, IBinding member, boolean isPointerDeref, IBinding templateDefinition) { this(ownerType, ownerValueCat, member, null, isPointerDeref, templateDefinition); } public EvalMemberAccess(IType ownerType, ValueCategory ownerValueCat, IBinding member, ICPPEvaluation ownerEval, boolean isDeref, IASTNode pointOfDefinition) { this(ownerType, ownerValueCat, member, ownerEval, isDeref, findEnclosingTemplate(pointOfDefinition)); } public EvalMemberAccess(IType ownerType, ValueCategory ownerValueCat, IBinding member, ICPPEvaluation ownerEval, boolean isDeref, IBinding templateDefinition) { super(templateDefinition); fOwnerType = ownerType; fOwnerValueCategory = ownerValueCat; fMember = member; fIsPointerDeref = isDeref; fOwnerEval = ownerEval; } public IType getOwnerType() { return fOwnerType; } public ValueCategory getOwnerValueCategory() { return fOwnerValueCategory; } public ICPPEvaluation getOwnerEval() { return fOwnerEval; } public IBinding getMember() { return fMember; } public boolean isPointerDeref() { return fIsPointerDeref; } @Override public boolean isInitializerList() { return false; } @Override public boolean isFunctionSet() { return false; } @Override public boolean isTypeDependent() { if (!fCheckedIsTypeDependent) { fCheckedIsTypeDependent = true; fIsTypeDependent = computeIsTypeDependent(); } return fIsTypeDependent; } private boolean computeIsTypeDependent() { IType t; if (fMember instanceof ICPPUnknownBinding) { return true; } else if (fMember instanceof IEnumerator) { t = ((IEnumerator) fMember).getType(); } else if (fMember instanceof IVariable) { t = ((IVariable) fMember).getType(); } else if (fMember instanceof IFunction) { t = ((IFunction) fMember).getType(); } else { return false; } return CPPTemplates.isDependentType(t); } @Override public boolean isValueDependent() { if (!fCheckedIsValueDependent) { fCheckedIsValueDependent = true; fIsValueDependent = computeIsValueDependent(); } return fIsValueDependent; } private boolean computeIsValueDependent() { if (fMember instanceof ICPPUnknownBinding) { return true; } if (fMember instanceof IEnumerator) { return IntegralValue.isDependentValue(((IEnumerator) fMember).getValue()); } if (fMember instanceof IVariable) { return IntegralValue.isDependentValue(((IVariable) fMember).getInitialValue()); } if (fMember instanceof IFunction) { return false; } return false; } @Override public boolean isConstantExpression(IASTNode point) { if (fOwnerEval != null) { return fOwnerEval.isConstantExpression(point); } return false; } public static IType getFieldOwnerType(IType fieldOwnerExpressionType, boolean isDeref, IASTNode point, Collection<ICPPFunction> functionBindings, boolean returnDependent) { IType type= fieldOwnerExpressionType; if (!isDeref) return type; // Bug 205964: as long as the type is a class type, recurse. // Be defensive and allow a max of 20 levels. for (int j = 0; j < 20; j++) { IType classType= getUltimateTypeUptoPointers(type); if (!(classType instanceof ICPPClassType)) break; IScope scope = ((ICPPClassType) classType).getCompositeScope(); if (scope == null || scope instanceof ICPPInternalUnknownScope) break; /* * 13.5.6-1: An expression x->m is interpreted as (x.operator->())->m for a * class object x of type T * * Construct an AST fragment for x.operator-> which the lookup routines can * examine for type information. */ ICPPEvaluation[] args= { new EvalFixed(type, LVALUE, IntegralValue.UNKNOWN) }; ICPPFunction op= CPPSemantics.findOverloadedOperator(point, null, args, classType, OverloadableOperator.ARROW, LookupMode.NO_GLOBALS); if (op == null) break; if (functionBindings != null) functionBindings.add(op); type = typeFromFunctionCall(op); type = SemanticUtil.mapToAST(type, point); } IType prValue = prvalueTypeWithResolvedTypedefs(type); if (prValue instanceof IPointerType) { return glvalueType(((IPointerType) prValue).getType()); } if (CPPTemplates.isDependentType(type)) { return returnDependent // The type resulting from dereferecing 'type' ? new TypeOfDependentExpression(new EvalUnary(IASTUnaryExpression.op_star, new EvalFixed(type, LVALUE, IntegralValue.UNKNOWN), null, point)) : null; } return ProblemType.UNKNOWN_FOR_EXPRESSION; } @Override public IType getType(IASTNode point) { if (fType == null) { fType = computeType(point); } return fType; } private IType computeType(IASTNode point) { if (fMember instanceof ICPPUnknownBinding) { return new TypeOfDependentExpression(this); } if (fMember instanceof IEnumerator) { return ((IEnumerator) fMember).getType(); } if (fMember instanceof IVariable) { IType e2 = ((IVariable) fMember).getType(); e2 = SemanticUtil.getNestedType(e2, TDEF); if (e2 instanceof ICPPReferenceType) { e2 = glvalueType(e2); } else if (fMember instanceof ICPPField && !((ICPPField) fMember).isStatic()) { e2 = addQualifiersForAccess((ICPPField) fMember, e2, fOwnerType); if (!fIsPointerDeref && fOwnerValueCategory == PRVALUE) { e2 = prvalueType(e2); } else { e2 = glvalueType(e2); } } return SemanticUtil.mapToAST(e2, point); } if (fMember instanceof IFunction) { return SemanticUtil.mapToAST(((IFunction) fMember).getType(), point); } return ProblemType.UNKNOWN_FOR_EXPRESSION; } private IType addQualifiersForAccess(ICPPField field, IType fieldType, IType ownerType) { CVQualifier cvq1 = SemanticUtil.getCVQualifier(ownerType); CVQualifier cvq2 = SemanticUtil.getCVQualifier(fieldType); if (field.isMutable()) { // Remove const, add union of volatile. if (cvq2.isConst()) { fieldType = SemanticUtil.getNestedType(fieldType, ALLCVQ | TDEF | REF); } fieldType = SemanticUtil.addQualifiers(fieldType, false, cvq1.isVolatile() || cvq2.isVolatile(), cvq2.isRestrict()); } else { fieldType = SemanticUtil.addQualifiers(fieldType, cvq1.isConst(), cvq1.isVolatile(), cvq2.isRestrict()); } return fieldType; } @Override public IValue getValue(IASTNode point) { if (fOwnerEval != null) { int fieldPos = CPPASTFieldReference.getFieldPosition(fMember, fOwnerType); IValue ownerValue = fOwnerEval.getValue(point); if (ownerValue instanceof CompositeValue) { CompositeValue compValue = (CompositeValue) ownerValue; ICPPEvaluation field = compValue.getSubValue(fieldPos); if (field != null) { return field.getValue(point); } } else { return IntegralValue.UNKNOWN; } } if (fMember instanceof IEnumerator) { return ((IEnumerator) fMember).getValue(); } if (fMember instanceof IVariable) { IValue initialValue = ((IVariable) fMember).getInitialValue(); return initialValue == null ? IntegralValue.UNKNOWN : initialValue; } if (fMember instanceof IFunction) { return IntegralValue.UNKNOWN; } return DependentValue.create(this); } @Override public ValueCategory getValueCategory(IASTNode point) { if (fMember instanceof IVariable) { IType e2 = ((IVariable) fMember).getType(); e2 = SemanticUtil.getNestedType(e2, TDEF); if (e2 instanceof ICPPReferenceType) { return LVALUE; } if (fMember instanceof ICPPField && !((ICPPField) fMember).isStatic()) { if (fIsPointerDeref) return LVALUE; return fOwnerValueCategory; } return LVALUE; } if (fMember instanceof IFunction) { return LVALUE; } return PRVALUE; } @Override public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { short firstBytes = ITypeMarshalBuffer.EVAL_MEMBER_ACCESS; if (fIsPointerDeref) firstBytes |= ITypeMarshalBuffer.FLAG1; if (fOwnerValueCategory == LVALUE) { firstBytes |= ITypeMarshalBuffer.FLAG2; } else if (fOwnerValueCategory == XVALUE) { firstBytes |= ITypeMarshalBuffer.FLAG3; } buffer.putShort(firstBytes); buffer.marshalType(fOwnerType); buffer.marshalBinding(fMember); buffer.marshalEvaluation(fOwnerEval, includeValue); marshalTemplateDefinition(buffer); } public static ICPPEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException { boolean isDeref = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0; ValueCategory ownerValueCat; if ((firstBytes & ITypeMarshalBuffer.FLAG2) != 0) { ownerValueCat = LVALUE; } else if ((firstBytes & ITypeMarshalBuffer.FLAG3) != 0) { ownerValueCat = XVALUE; } else { ownerValueCat = PRVALUE; } IType ownerType = buffer.unmarshalType(); IBinding member = buffer.unmarshalBinding(); ICPPEvaluation ownerEval = buffer.unmarshalEvaluation(); IBinding templateDefinition = buffer.unmarshalBinding(); return new EvalMemberAccess(ownerType, ownerValueCat, member, ownerEval, isDeref, templateDefinition); } @Override public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) { IType ownerType = CPPTemplates.instantiateType(fOwnerType, context); if (ownerType == fOwnerType && fOwnerEval == null) return this; IBinding member = fMember; IType ownerClass = SemanticUtil.getNestedType(ownerType, ALLCVQ); if (ownerClass instanceof ICPPClassSpecialization) { member = CPPTemplates.createSpecialization((ICPPClassSpecialization) ownerClass, fMember, context.getPoint()); } ICPPEvaluation ownerEval = fOwnerEval; if (ownerEval != null) { ownerEval = ownerEval.instantiate(context, maxDepth); if (ownerType == fOwnerType && ownerEval == fOwnerEval) return this; } return new EvalMemberAccess(ownerType, fOwnerValueCategory, member, ownerEval, fIsPointerDeref, getTemplateDefinition()); } private boolean isMemberAccessThroughThisPointer() { if (fOwnerEval == null) { return true; } else if (fOwnerEval instanceof EvalFixed) { EvalFixed evalFixed = (EvalFixed) fOwnerEval; return evalFixed.getValue() == IntegralValue.THIS; } return false; } private ICPPEvaluation getOwnerEval(ActivationRecord record) { if (isMemberAccessThroughThisPointer()) { return record.getImplicitThis(); } return fOwnerEval; } @Override public ICPPEvaluation computeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) { final ICPPEvaluation ownerEval = getOwnerEval(record); if (fMember instanceof ICPPMethod) { EvalBinding evalBinding = new EvalBinding(fMember, fType, getTemplateDefinition()); return evalBinding; } if (ownerEval == null) { return this; } int fieldPos = CPPASTFieldReference.getFieldPosition(fMember, fOwnerType); ICPPEvaluation evaluatedOwner = ownerEval.computeForFunctionCall(record, context); if (evaluatedOwner instanceof EvalPointer) { evaluatedOwner = ((EvalPointer) evaluatedOwner).dereference(); } if (fMember instanceof ICPPField) { ICPPField field = (ICPPField) fMember; if (field.getType() instanceof IArrayType) { EvalPointer evalPointer = new EvalPointer(record, new EvalCompositeAccess(new EvalCompositeAccess(evaluatedOwner, fieldPos), 0), getTemplateDefinition()); return evalPointer; } } EvalReference evalRef = new EvalReference(record, new EvalCompositeAccess(evaluatedOwner, fieldPos), getTemplateDefinition()); return evalRef; } @Override public int determinePackSize(ICPPTemplateParameterMap tpMap) { return CPPTemplates.determinePackSize(fOwnerType, tpMap); } @Override public boolean referencesTemplateParameter() { return false; } }