/******************************************************************************* * 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 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.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; 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; public class EvalReference extends CPPDependentEvaluation { protected final ActivationRecord owningRecord; // The following invariant must be true for instances of this class: // (referredBinding == null) != (referredSubValue == null) protected IBinding referredBinding; protected EvalCompositeAccess referredSubValue; EvalReference(ActivationRecord owningRecord, IBinding referredBinding, IBinding templateDefinition) { super(templateDefinition); this.owningRecord = owningRecord; this.referredBinding = referredBinding; } EvalReference(ActivationRecord owningRecord, IBinding referredBinding, IASTNode point) { this(owningRecord, referredBinding, findEnclosingTemplate(point)); } EvalReference(ActivationRecord owningRecord, EvalCompositeAccess referredSubValue, IBinding templateDefinition) { super(templateDefinition); this.owningRecord = owningRecord; this.referredSubValue = referredSubValue; this.referredBinding = null; } EvalReference(ActivationRecord owningRecord, EvalCompositeAccess referredSubValue, IASTNode point) { this(owningRecord, referredSubValue, findEnclosingTemplate(point)); } @Override public final boolean isInitializerList() { return getTargetEvaluation().isInitializerList(); } @Override public final boolean isFunctionSet() { return getTargetEvaluation().isFunctionSet(); } @Override public final boolean isTypeDependent() { return getTargetEvaluation().isTypeDependent(); } @Override public final boolean isValueDependent() { return getTargetEvaluation().isValueDependent(); } @Override public final boolean isConstantExpression(IASTNode point) { return getTargetEvaluation().isConstantExpression(point); } @Override public IType getType(IASTNode point) { return getTargetEvaluation().getType(point); } @Override public IValue getValue(IASTNode point) { return getTargetEvaluation().getValue(point); } public final ICPPEvaluation getTargetEvaluation() { if (referredSubValue != null) { return referredSubValue; } ICPPEvaluation targetValue = owningRecord.getVariable(referredBinding); return targetValue == null ? EvalFixed.INCOMPLETE : targetValue; } public void update(ICPPEvaluation eval) { if (referredBinding != null) { ICPPEvaluation oldValue = owningRecord.getVariable(referredBinding); if (oldValue instanceof EvalReference) { ((EvalReference) oldValue).update(eval); } else { owningRecord.update(referredBinding, eval); } } else { referredSubValue.update(eval); } } public final IBinding getReferredBinding() { return referredBinding; } @Override public ValueCategory getValueCategory(IASTNode point) { return getTargetEvaluation().getValueCategory(point); } @Override public ICPPEvaluation computeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) { if (referredSubValue != null) { return referredSubValue.computeForFunctionCall(record, context); } ICPPEvaluation referredEval = owningRecord.getVariable(referredBinding); if (referredEval instanceof EvalReference) { // TODO(nathanridge): Why are we doing this for EvalReference only? return referredEval.computeForFunctionCall(record, context); } return referredEval; } @Override public int determinePackSize(ICPPTemplateParameterMap tpMap) { return getTargetEvaluation().determinePackSize(tpMap); } @Override public boolean referencesTemplateParameter() { return getTargetEvaluation().referencesTemplateParameter(); } @Override public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) { // TODO(nathanridge): Why are we losing the EvalReference wrapper here? return getTargetEvaluation().instantiate(context, maxDepth); } @Override public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { short firstBytes = ITypeMarshalBuffer.EVAL_REFERENCE; if (referredSubValue != null) { firstBytes |= ITypeMarshalBuffer.FLAG1; } buffer.putShort(firstBytes); if (referredSubValue != null) { buffer.marshalEvaluation(referredSubValue, includeValue); } else { buffer.marshalBinding(referredBinding); buffer.marshalEvaluation(owningRecord.getVariable(referredBinding), includeValue); } marshalTemplateDefinition(buffer); } public static ICPPEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException { boolean subValue = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0; if (subValue) { EvalCompositeAccess referredSubValue = (EvalCompositeAccess) buffer.unmarshalEvaluation(); IBinding templateDefinition = buffer.unmarshalBinding(); return new EvalReference(new ActivationRecord(), referredSubValue, templateDefinition); } else { IBinding referredBinding = buffer.unmarshalBinding(); ICPPEvaluation value = buffer.unmarshalEvaluation(); ActivationRecord record = new ActivationRecord(); record.update(referredBinding, value); IBinding templateDefinition = buffer.unmarshalBinding(); return new EvalReference(record, referredBinding, templateDefinition); } } }