/******************************************************************************* * Copyright (c) 2004, 2015 IBM Corporation 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: * John Camelon (IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.DestructorCallCollector; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConditional; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed; public class CPPASTConditionalExpression extends ASTNode implements IASTConditionalExpression, ICPPASTExpression, IASTAmbiguityParent, ICPPEvaluationOwner { private ICPPASTExpression fCondition; private ICPPASTExpression fPositive; private ICPPASTExpression fNegative; private ICPPEvaluation fEval; private IASTImplicitDestructorName[] fImplicitDestructorNames; public CPPASTConditionalExpression() { } public CPPASTConditionalExpression(IASTExpression condition, IASTExpression postive, IASTExpression negative) { setLogicalConditionExpression(condition); setPositiveResultExpression(postive); setNegativeResultExpression(negative); } @Override public CPPASTConditionalExpression copy() { return copy(CopyStyle.withoutLocations); } @Override public CPPASTConditionalExpression copy(CopyStyle style) { CPPASTConditionalExpression copy = new CPPASTConditionalExpression(); copy.setLogicalConditionExpression(fCondition == null ? null : fCondition.copy(style)); copy.setPositiveResultExpression(fPositive == null ? null : fPositive.copy(style)); copy.setNegativeResultExpression(fNegative == null ? null : fNegative.copy(style)); return copy(copy, style); } @Override public IASTExpression getLogicalConditionExpression() { return fCondition; } @Override public void setLogicalConditionExpression(IASTExpression expression) { assertNotFrozen(); fCondition = (ICPPASTExpression) expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(LOGICAL_CONDITION); } } @Override public IASTExpression getPositiveResultExpression() { return fPositive; } @Override public void setPositiveResultExpression(IASTExpression expression) { assertNotFrozen(); this.fPositive = (ICPPASTExpression) expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(POSITIVE_RESULT); } } @Override public IASTExpression getNegativeResultExpression() { return fNegative; } @Override public void setNegativeResultExpression(IASTExpression expression) { assertNotFrozen(); this.fNegative = (ICPPASTExpression) expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(NEGATIVE_RESULT); } } @Override public IASTImplicitDestructorName[] getImplicitDestructorNames() { if (fImplicitDestructorNames == null) { fImplicitDestructorNames = DestructorCallCollector.getTemporariesDestructorCalls(this); } return fImplicitDestructorNames; } @Override public boolean accept(ASTVisitor action) { if (action.shouldVisitExpressions) { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; } } if (fCondition != null && !fCondition.accept(action)) return false; if (fPositive != null && !fPositive.accept(action)) return false; if (fNegative != null && !fNegative.accept(action)) return false; if (action.shouldVisitImplicitDestructorNames && !acceptByNodes(getImplicitDestructorNames(), action)) return false; if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT) return false; return true; } @Override public void replace(IASTNode child, IASTNode other) { if (child == fCondition) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); fCondition = (ICPPASTExpression) other; } if (child == fPositive) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); fPositive = (ICPPASTExpression) other; } if (child == fNegative) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); fNegative = (ICPPASTExpression) other; } } private boolean isThrowExpression(IASTExpression expr) { while (expr instanceof IASTUnaryExpression) { final IASTUnaryExpression unaryExpr = (IASTUnaryExpression) expr; final int op = unaryExpr.getOperator(); if (op == IASTUnaryExpression.op_throw) { return true; } else if (op == IASTUnaryExpression.op_bracketedPrimary) { expr= unaryExpr.getOperand(); } else { return false; } } return false; } @Override public ICPPEvaluation getEvaluation() { if (fEval == null) { if (fCondition == null || fNegative == null) { fEval= EvalFixed.INCOMPLETE; } else { final ICPPEvaluation condEval = ((ICPPEvaluationOwner) fCondition).getEvaluation(); final ICPPEvaluation posEval = fPositive == null ? null : ((ICPPEvaluationOwner) fPositive).getEvaluation(); final ICPPEvaluation negEval = ((ICPPEvaluationOwner) fNegative).getEvaluation(); fEval= new EvalConditional(condEval, posEval, negEval, isThrowExpression(fPositive), isThrowExpression(fNegative), this); } } return fEval; } @Override public IType getExpressionType() { return getEvaluation().getType(this); } @Override public ValueCategory getValueCategory() { return getEvaluation().getValueCategory(this); } @Override public boolean isLValue() { return getValueCategory() == LVALUE; } }