blob: 073bbf58e3a77505b5ef2a0072b41963d7522f17 [file] [log] [blame]
/*******************************************************************************
* 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
* Mike Kucera (IBM)
* 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.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName;
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.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
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.CPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.DestructorCallCollector;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinary;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpression, IASTAmbiguityParent {
private int fOperator;
private ICPPASTExpression fOperand1;
private ICPPASTInitializerClause fOperand2;
private ICPPEvaluation fEvaluation;
private IASTImplicitName[] fImplicitNames;
private IASTImplicitDestructorName[] fImplicitDestructorNames;
public CPPASTBinaryExpression() {
}
public CPPASTBinaryExpression(int op, IASTExpression operand1, IASTInitializerClause operand2) {
this.fOperator = op;
setOperand1(operand1);
setInitOperand2(operand2);
}
@Override
public CPPASTBinaryExpression copy() {
return copy(CopyStyle.withoutLocations);
}
@Override
public CPPASTBinaryExpression copy(CopyStyle style) {
CPPASTBinaryExpression copy = new CPPASTBinaryExpression(fOperator,
fOperand1 == null ? null : fOperand1.copy(style),
fOperand2 == null ? null : fOperand2.copy(style));
return copy(copy, style);
}
@Override
public int getOperator() {
return fOperator;
}
@Override
public IASTExpression getOperand1() {
return fOperand1;
}
@Override
public IASTInitializerClause getInitOperand2() {
return fOperand2;
}
@Override
public IASTExpression getOperand2() {
if (fOperand2 instanceof IASTExpression)
return (IASTExpression) fOperand2;
return null;
}
@Override
public void setOperator(int op) {
assertNotFrozen();
this.fOperator = op;
}
@Override
public void setOperand1(IASTExpression expression) {
assertNotFrozen();
if (expression != null) {
if (!(expression instanceof ICPPASTExpression))
throw new IllegalArgumentException(expression.getClass().getName());
expression.setParent(this);
expression.setPropertyInParent(OPERAND_ONE);
}
fOperand1 = (ICPPASTExpression) expression;
}
public void setInitOperand2(IASTInitializerClause operand) {
assertNotFrozen();
if (operand != null) {
if (!(operand instanceof ICPPASTInitializerClause))
throw new IllegalArgumentException(operand.getClass().getName());
operand.setParent(this);
operand.setPropertyInParent(OPERAND_TWO);
}
fOperand2 = (ICPPASTInitializerClause) operand;
}
@Override
public void setOperand2(IASTExpression expression) {
setInitOperand2(expression);
}
@Override
public IASTImplicitName[] getImplicitNames() {
if (fImplicitNames == null) {
ICPPFunction overload = getOverload();
if (overload == null || (overload instanceof CPPImplicitFunction && !(overload instanceof ICPPMethod))) {
fImplicitNames = IASTImplicitName.EMPTY_NAME_ARRAY;
} else {
CPPASTImplicitName operatorName = new CPPASTImplicitName(overload.getNameCharArray(), this);
operatorName.setBinding(overload);
operatorName.setOperator(true);
operatorName.computeOperatorOffsets(fOperand1, true);
fImplicitNames = new IASTImplicitName[] { operatorName };
}
}
return fImplicitNames;
}
@Override
public IASTImplicitDestructorName[] getImplicitDestructorNames() {
if (fImplicitDestructorNames == null) {
fImplicitDestructorNames = DestructorCallCollector.getTemporariesDestructorCalls(this);
}
return fImplicitDestructorNames;
}
@Override
public boolean accept(ASTVisitor action) {
if (fOperand1 instanceof IASTBinaryExpression || fOperand2 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 (fOperand1 != null && !fOperand1.accept(action))
return false;
if (action.shouldVisitImplicitNames && !acceptByNodes(getImplicitNames(), action))
return false;
if (fOperand2 != null && !fOperand2.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;
}
private static class N {
final IASTBinaryExpression fExpression;
int fState;
N fNext;
N(IASTBinaryExpression expr) {
fExpression = expr;
}
}
private 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 &&
!acceptByNodes(((IASTImplicitNameOwner) expr).getImplicitNames(), action)) {
return false;
}
stack.fState= 2;
IASTInitializerClause op2 = expr.getInitOperand2();
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;
}
@Override
public void replace(IASTNode child, IASTNode other) {
if (child == fOperand1) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
fOperand1 = (ICPPASTExpression) other;
}
if (child == fOperand2) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
fOperand2 = (ICPPASTInitializerClause) other;
}
}
@Override
public ICPPFunction getOverload() {
ICPPEvaluation eval = getEvaluation();
if (eval instanceof EvalBinary) {
CPPSemantics.pushLookupPoint(this);
try {
return ((EvalBinary) eval).getOverload();
} finally {
CPPSemantics.popLookupPoint();
}
}
return null;
}
@Override
public ICPPEvaluation getEvaluation() {
if (fEvaluation == null)
fEvaluation= computeEvaluation();
return fEvaluation;
}
private ICPPEvaluation computeEvaluation() {
if (fOperand1 == null || fOperand2 == null)
return EvalFixed.INCOMPLETE;
ICPPEvaluation eval1 = fOperand1.getEvaluation();
ICPPEvaluation eval2 = fOperand2.getEvaluation();
return new EvalBinary(fOperator, eval1, eval2, this);
}
@Override
public IType getExpressionType() {
return CPPEvaluation.getType(this);
}
@Override
public ValueCategory getValueCategory() {
return CPPEvaluation.getValueCategory(this);
}
@Override
public boolean isLValue() {
return getValueCategory() == LVALUE;
}
}