/******************************************************************************* * Copyright (c) 2004, 2011 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 * Mike Kucera (IBM) * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; 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.ExpressionTypes.*; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTImplicitName; import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; 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.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpression, IASTAmbiguityParent { private int op; private IASTExpression operand1; private IASTInitializerClause operand2; private IType type; private ICPPFunction overload= UNINITIALIZED_FUNCTION; private IASTImplicitName[] implicitNames = null; public CPPASTBinaryExpression() { } public CPPASTBinaryExpression(int op, IASTExpression operand1, IASTInitializerClause operand2) { this.op = op; setOperand1(operand1); setInitOperand2(operand2); } public CPPASTBinaryExpression copy() { return copy(CopyStyle.withoutLocations); } public CPPASTBinaryExpression copy(CopyStyle style) { CPPASTBinaryExpression copy = new CPPASTBinaryExpression(); copy.op = op; copy.setOperand1(operand1 == null ? null : operand1.copy(style)); copy.setInitOperand2(operand2 == null ? null : operand2.copy(style)); copy.setOffsetAndLength(this); if (style == CopyStyle.withLocations) { copy.setCopyLocation(this); } return copy; } public int getOperator() { return op; } public IASTExpression getOperand1() { return operand1; } public IASTInitializerClause getInitOperand2() { return operand2; } public IASTExpression getOperand2() { if (operand2 instanceof IASTExpression) return (IASTExpression) operand2; return null; } public void setOperator(int op) { assertNotFrozen(); this.op = op; } public void setOperand1(IASTExpression expression) { assertNotFrozen(); operand1 = expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(OPERAND_ONE); } } public void setInitOperand2(IASTInitializerClause operand) { assertNotFrozen(); operand2 = operand; if (operand != null) { operand.setParent(this); operand.setPropertyInParent(OPERAND_TWO); } } public void setOperand2(IASTExpression expression) { setInitOperand2(expression); } /** * @see org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner#getImplicitNames() */ public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { ICPPFunction overload = getOverload(); if (overload == null || (overload instanceof CPPImplicitFunction && !(overload instanceof ICPPMethod))) { implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; } else { CPPASTImplicitName operatorName = new CPPASTImplicitName(overload.getNameCharArray(), this); operatorName.setBinding(overload); operatorName.setOperator(true); operatorName.computeOperatorOffsets(operand1, true); implicitNames = new IASTImplicitName[] { operatorName }; } } return implicitNames; } @Override public boolean accept(ASTVisitor action) { if (operand1 instanceof IASTBinaryExpression || operand2 instanceof IASTBinaryExpression) { return acceptWithoutRecursion(this, action); } if (action.shouldVisitExpressions) { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; } } if (operand1 != null && !operand1.accept(action)) return false; if (action.shouldVisitImplicitNames) { for (IASTImplicitName name : getImplicitNames()) { if (!name.accept(action)) return false; } } if (operand2 != null && !operand2.accept(action)) return false; if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT) return false; return true; } private static class N { final IASTBinaryExpression fExpression; int fState; N fNext; N(IASTBinaryExpression expr) { fExpression = expr; } } public static boolean acceptWithoutRecursion(IASTBinaryExpression bexpr, ASTVisitor action) { N stack= new N(bexpr); while (stack != null) { IASTBinaryExpression expr= stack.fExpression; if (stack.fState == 0) { if (action.shouldVisitExpressions) { switch (action.visit(expr)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: stack= stack.fNext; continue; } } stack.fState= 1; IASTExpression op1 = expr.getOperand1(); if (op1 instanceof IASTBinaryExpression) { N n= new N((IASTBinaryExpression) op1); n.fNext= stack; stack= n; continue; } if (op1 != null && !op1.accept(action)) return false; } if (stack.fState == 1) { if (action.shouldVisitImplicitNames) { for (IASTImplicitName name : ((IASTImplicitNameOwner) expr).getImplicitNames()) { if (!name.accept(action)) return false; } } stack.fState= 2; IASTExpression op2 = expr.getOperand2(); if (op2 instanceof IASTBinaryExpression) { N n= new N((IASTBinaryExpression) op2); n.fNext= stack; stack= n; continue; } if (op2 != null && !op2.accept(action)) return false; } if (action.shouldVisitExpressions && action.leave(expr) == ASTVisitor.PROCESS_ABORT) return false; stack= stack.fNext; } return true; } public void replace(IASTNode child, IASTNode other) { if (child == operand1) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); operand1 = (IASTExpression) other; } if (child == operand2) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); operand2 = (IASTInitializerClause) other; } } public IType getExpressionType() { if (type == null) { type= createExpressionType(); } return type; } public ICPPFunction getOverload() { if (overload != UNINITIALIZED_FUNCTION) return overload; return overload = CPPSemantics.findOverloadedOperator(this); } public ValueCategory getValueCategory() { ICPPFunction op = getOverload(); if (op != null) { return valueCategoryFromFunctionCall(op); } switch (getOperator()) { case op_assign: case op_binaryAndAssign: case op_binaryOrAssign: case op_binaryXorAssign: case op_divideAssign: case op_minusAssign: case op_moduloAssign: case op_multiplyAssign: case op_plusAssign: case op_shiftLeftAssign: case op_shiftRightAssign: return LVALUE; case op_pmdot: if (!(getExpressionType() instanceof ICPPFunctionType)) { return operand1.getValueCategory(); } return PRVALUE; case op_pmarrow: if (!(getExpressionType() instanceof ICPPFunctionType)) return LVALUE; return PRVALUE; } return PRVALUE; } public boolean isLValue() { return getValueCategory() == LVALUE; } private IType createExpressionType() { // Check for overloaded operator. ICPPFunction o= getOverload(); if (o != null) { return typeFromFunctionCall(o); } final int op = getOperator(); IType type1 = prvalueType(operand1.getExpressionType()); if (type1 instanceof ISemanticProblem) { return type1; } IType type2 = null; if (operand2 instanceof IASTExpression) { type2= prvalueType(((IASTExpression) operand2).getExpressionType()); if (type2 instanceof ISemanticProblem) { return type2; } } IType type= CPPArithmeticConversion.convertCppOperandTypes(op, type1, type2); if (type != null) { return type; } switch (op) { case IASTBinaryExpression.op_lessEqual: case IASTBinaryExpression.op_lessThan: case IASTBinaryExpression.op_greaterEqual: case IASTBinaryExpression.op_greaterThan: case IASTBinaryExpression.op_logicalAnd: case IASTBinaryExpression.op_logicalOr: case IASTBinaryExpression.op_equals: case IASTBinaryExpression.op_notequals: return CPPBasicType.BOOLEAN; case IASTBinaryExpression.op_plus: if (type1 instanceof IPointerType) { return type1; } if (type2 instanceof IPointerType) { return type2; } break; case IASTBinaryExpression.op_minus: if (type1 instanceof IPointerType) { if (type2 instanceof IPointerType) { return CPPVisitor.getPointerDiffType(this); } return type1; } break; case ICPPASTBinaryExpression.op_pmarrow: case ICPPASTBinaryExpression.op_pmdot: if (type2 instanceof ICPPPointerToMemberType) { IType t= ((ICPPPointerToMemberType) type2).getType(); if (t instanceof ICPPFunctionType) return t; if (op == ICPPASTBinaryExpression.op_pmdot && operand1.getValueCategory() == PRVALUE) { return prvalueType(t); } return glvalueType(t); } return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); } return type1; } }