/******************************************************************************* * Copyright (c) 2004, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying masterials * 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 * Sergey Prigogin (Google) * 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 static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTImplicitName; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember; 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.ITypeContainer; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; 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; /** * Unary expression in c++ */ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpression, IASTAmbiguityParent { private int op; private IASTExpression operand; private ICPPFunction overload = UNINITIALIZED_FUNCTION; private IASTImplicitName[] implicitNames = null; public CPPASTUnaryExpression() { } public CPPASTUnaryExpression(int operator, IASTExpression operand) { op = operator; setOperand(operand); } public CPPASTUnaryExpression copy() { return copy(CopyStyle.withoutLocations); } public CPPASTUnaryExpression copy(CopyStyle style) { CPPASTUnaryExpression copy = new CPPASTUnaryExpression(op, operand == null ? null : operand.copy(style)); copy.setOffsetAndLength(this); if (style == CopyStyle.withLocations) { copy.setCopyLocation(this); } return copy; } public int getOperator() { return op; } public void setOperator(int operator) { assertNotFrozen(); op = operator; } public IASTExpression getOperand() { return operand; } public void setOperand(IASTExpression expression) { assertNotFrozen(); operand = expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(OPERAND); } } public boolean isPostfixOperator() { return op == op_postFixDecr || op == op_postFixIncr; } /** * @see org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner#getImplicitNames() */ public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { ICPPFunction overload = getOverload(); if (overload == null || overload instanceof CPPImplicitFunction) { implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; } else { CPPASTImplicitName operatorName = new CPPASTImplicitName(overload.getNameCharArray(), this); operatorName.setOperator(true); operatorName.setBinding(overload); operatorName.computeOperatorOffsets(operand, isPostfixOperator()); implicitNames = new IASTImplicitName[] { operatorName }; } } return implicitNames; } @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; } } final boolean isPostfix = isPostfixOperator(); if (!isPostfix && action.shouldVisitImplicitNames) { for (IASTImplicitName name : getImplicitNames()) { if (!name.accept(action)) return false; } } if (operand != null && !operand.accept(action)) return false; if (isPostfix && action.shouldVisitImplicitNames) { for (IASTImplicitName name : getImplicitNames()) { if (!name.accept(action)) return false; } } if (action.shouldVisitExpressions) { switch (action.leave(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; } } return true; } public void replace(IASTNode child, IASTNode other) { if (child == operand) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); operand = (IASTExpression) other; } } public ICPPFunction getOverload() { if (overload != UNINITIALIZED_FUNCTION) return overload; overload = CPPSemantics.findOverloadedOperator(this); if (overload != null && op == op_amper && computePointerToMemberType() instanceof CPPPointerToMemberType) overload = null; return overload; } private IType computePointerToMemberType() { IASTNode child= operand; boolean inParenthesis= false; while (child instanceof IASTUnaryExpression && ((IASTUnaryExpression) child).getOperator() == IASTUnaryExpression.op_bracketedPrimary) { child= ((IASTUnaryExpression) child).getOperand(); inParenthesis= true; } if (child instanceof IASTIdExpression) { IASTName name= ((IASTIdExpression) child).getName(); IBinding b= name.resolveBinding(); if (b instanceof ICPPMember) { ICPPMember member= (ICPPMember) b; try { if (name instanceof ICPPASTQualifiedName) { if (!member.isStatic()) { // so if the member is static it will fall through overload= null; if (!inParenthesis) { return new CPPPointerToMemberType(member.getType(), member.getClassOwner(), false, false, false); } else if (member instanceof IFunction) { return new ProblemBinding(operand, IProblemBinding.SEMANTIC_INVALID_TYPE, operand.getRawSignature().toCharArray()); } } } } catch (DOMException e) { return e.getProblem(); } } } return null; } public IType getExpressionType() { final int op= getOperator(); switch (op) { case op_sizeof: case op_sizeofParameterPack: return CPPVisitor.get_SIZE_T(this); case op_typeid: return CPPVisitor.get_type_info(this); case op_bracketedPrimary: return getOperand().getExpressionType(); case op_throw: return CPPSemantics.VOID_TYPE; } final IASTExpression operand = getOperand(); if (op == op_amper) { // check for pointer to member IType ptm = computePointerToMemberType(); if (ptm != null) return ptm; ICPPFunction overload = getOverload(); if (overload != null) return typeFromFunctionCall(overload); return new CPPPointerType(operand.getExpressionType()); } ICPPFunction overload = getOverload(); if (overload != null) return typeFromFunctionCall(overload); if (op == op_star) { IType type= operand.getExpressionType(); type = prvalueType(type); if (type instanceof IPointerType) { type= ((ITypeContainer) type).getType(); return glvalueType(type); } if (type instanceof ISemanticProblem) { return type; } type= getUltimateTypeUptoPointers(type); if (type instanceof ICPPUnknownType) { // mstodo Type of unknown return CPPUnknownClass.createUnnamedInstance(); } return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); } IType typeOfOperand= operand.getExpressionType(); switch (op) { case op_not: return CPPBasicType.BOOLEAN; case op_postFixDecr: case op_postFixIncr: typeOfOperand= prvalueType(typeOfOperand); break; case op_minus: case op_plus: case op_tilde: IType t= CPPArithmeticConversion.promoteCppType(prvalueType(typeOfOperand)); if (t != null) { return t; } break; } if (typeOfOperand instanceof CPPBasicType) { ((CPPBasicType) typeOfOperand).setFromExpression(this); } return typeOfOperand; } public ValueCategory getValueCategory() { final int op= getOperator(); switch (op) { case op_typeid: return LVALUE; case op_sizeof: case op_sizeofParameterPack: return PRVALUE; case op_bracketedPrimary: return (operand).getValueCategory(); } if (op == op_amper && computePointerToMemberType() != null) { return PRVALUE; } ICPPFunction overload = getOverload(); if (overload != null) return valueCategoryFromFunctionCall(overload); switch(op) { case op_star: case op_prefixDecr: case op_prefixIncr: return LVALUE; } return PRVALUE; } public boolean isLValue() { return getValueCategory() == LVALUE; } }