/******************************************************************************* * 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.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.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.IntegralValue; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.core.runtime.CoreException; public final class EvalPointer extends EvalReference { // The position will only be nonzero if the EvalReference has a referredSubValue, // not a referredBinding. private int position; public EvalPointer(ActivationRecord record, EvalCompositeAccess referredSubValue, IASTNode point) { this(record, referredSubValue, findEnclosingTemplate(point)); } public EvalPointer(ActivationRecord record, EvalCompositeAccess referredSubValue, IBinding templateDefinition) { this(record, referredSubValue, templateDefinition, referredSubValue.getElementId()); } public EvalPointer(ActivationRecord record, EvalCompositeAccess referredSubValue, IBinding templateDefinition, int offset) { super(record, referredSubValue, templateDefinition); setPosition(offset); } public EvalPointer(ActivationRecord record, IBinding referredBinding, IBinding templateDefinition) { super(record, referredBinding, templateDefinition); setPosition(0); } public EvalReference dereference() { if (referredSubValue != null) { final EvalCompositeAccess pointedToValue = new EvalCompositeAccess(referredSubValue.getParent(), getPosition()); return new EvalReference(owningRecord, pointedToValue, getTemplateDefinition()); } else { return new EvalReference(owningRecord,referredBinding, getTemplateDefinition()); } } @Override public IType getType(IASTNode point) { IType valueType = getTargetEvaluation().getType(point); return new CPPPointerType(valueType, false, false, false); } public int getPosition() { return position; } public void setPosition(int position) { this.position = position; invalidatePointerIfPositionOutOfRange(); } private void invalidatePointerIfPositionOutOfRange() { if (isPositionOutOfRange()) { referredSubValue = new EvalCompositeAccess(EvalFixed.INCOMPLETE, 0); referredBinding = null; } } private boolean isPositionOutOfRange() { return subValuePositionOutOfrange() || (this.referredBinding != null && position != 0); } private boolean subValuePositionOutOfrange() { return referredSubValue != null && (position - referredSubValue.getParent().getValue(null).numberOfSubValues() > 0 || position < 0); } @Override public IValue getValue(IASTNode point) { // TODO(nathanridge): Why does it make sense to consider a pointer's value to be its offset // into the underlying array? return IntegralValue.create(position); } @Override public ICPPEvaluation computeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) { return this; } public EvalPointer copy() { if (referredSubValue != null) { return new EvalPointer(owningRecord, referredSubValue, getTemplateDefinition(), position); } else { return new EvalPointer(owningRecord, referredBinding, getTemplateDefinition()); } } public static EvalPointer createFromAddress(EvalReference reference) { if (reference.referredSubValue != null) { return new EvalPointer(reference.owningRecord, reference.referredSubValue, reference.getTemplateDefinition()); } else { return new EvalPointer(reference.owningRecord, reference.referredBinding, reference.getTemplateDefinition()); } } @Override public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { short firstBytes = ITypeMarshalBuffer.EVAL_POINTER; if (referredSubValue != null) { firstBytes |= ITypeMarshalBuffer.FLAG1; } buffer.putShort(firstBytes); if (referredSubValue != null) { buffer.marshalEvaluation(referredSubValue, includeValue); buffer.putInt(position); } 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(); int position = buffer.getInt(); IBinding templateDefinition = buffer.unmarshalBinding(); return new EvalPointer(new ActivationRecord(), referredSubValue, templateDefinition, position); } else { IBinding referredBinding = buffer.unmarshalBinding(); ICPPEvaluation value = buffer.unmarshalEvaluation(); ActivationRecord record = new ActivationRecord(); record.update(referredBinding, value); IBinding templateDefinition = buffer.unmarshalBinding(); return new EvalPointer(record, referredBinding, templateDefinition); } } }