/******************************************************************************* * Copyright (c) 2008, 2014 Wind River Systems, Inc. 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: * Markus Schorn - initial API and implementation * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_alignof; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_nothrow_constructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_nothrow_copy; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_assign; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_constructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_copy; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_destructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_virtual_destructor; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_abstract; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_class; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_empty; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_enum; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_final; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_literal_type; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_pod; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_polymorphic; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_standard_layout; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_trivial; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_trivially_copyable; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_union; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_sizeof; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeid; import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeof; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluationOwner; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.TypeTraits; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException; public class ValueFactory { /** * Creates the value for an expression. */ public static IValue create(IASTExpression expr) { IValue val= evaluate(expr); if (val != null) { return val; } if (expr instanceof ICPPEvaluationOwner) { ICPPEvaluation evaluation = ((ICPPEvaluationOwner) expr).getEvaluation(); return evaluation.getValue(expr); } return IntegralValue.UNKNOWN; } public static IValue evaluateUnaryExpression(final int unaryOp, final IValue value) { IValue val = applyUnaryOperator(unaryOp, value); if (isInvalidValue(val)) return IntegralValue.UNKNOWN; return val; } public static IValue evaluateBinaryExpression(final int op, final IValue v1, final IValue v2) { if (v1 instanceof FloatingPointValue && v2 instanceof FloatingPointValue) { FloatingPointValue fv1 = (FloatingPointValue) v1; FloatingPointValue fv2 = (FloatingPointValue) v2; return applyBinaryOperator(op, fv1.numberValue().doubleValue(), fv2.numberValue().doubleValue()); } else if (v1 instanceof FloatingPointValue && v2 instanceof IntegralValue) { FloatingPointValue fv1 = (FloatingPointValue) v1; IntegralValue iv2 = (IntegralValue) v2; return applyBinaryOperator(op, fv1.numberValue().doubleValue(), iv2.numberValue().doubleValue()); } else if (v1 instanceof IntegralValue && v2 instanceof FloatingPointValue) { IntegralValue iv1 = (IntegralValue) v1; FloatingPointValue fv2 = (FloatingPointValue) v2; return applyBinaryOperator(op, iv1.numberValue().doubleValue(), fv2.numberValue().doubleValue()); } else if (v1 instanceof IntegralValue && v2 instanceof IntegralValue) { IntegralValue iv1 = (IntegralValue) v1; IntegralValue iv2 = (IntegralValue) v2; return applyBinaryOperator(op, iv1.numberValue().longValue(), iv2.numberValue().longValue()); } return IntegralValue.UNKNOWN; } private static IValue applyBinaryOperator(final int op, final double v1, final double v2) { Double doubleValue = null; Long longValue = null; switch (op) { case IASTBinaryExpression.op_multiply: doubleValue = v1 * v2; break; case IASTBinaryExpression.op_divide: if (v2 != 0) { doubleValue = v1 / v2; } break; case IASTBinaryExpression.op_plus: doubleValue = v1 + v2; break; case IASTBinaryExpression.op_minus: doubleValue = v1 - v2; break; case IASTBinaryExpression.op_lessThan: longValue = v1 < v2 ? 1l : 0l; break; case IASTBinaryExpression.op_greaterThan: longValue = v1 > v2 ? 1l : 0l; break; case IASTBinaryExpression.op_lessEqual: longValue = v1 <= v2 ? 1l : 0l; break; case IASTBinaryExpression.op_greaterEqual: longValue = v1 >= v2 ? 1l : 0l; break; case IASTBinaryExpression.op_logicalAnd: longValue = v1 != 0 && v2 != 0 ? 1l : 0l; break; case IASTBinaryExpression.op_logicalOr: longValue = v1 != 0 || v2 != 0 ? 1l : 0l; break; case IASTBinaryExpression.op_equals: longValue = v1 == v2 ? 1l : 0l; break; case IASTBinaryExpression.op_notequals: longValue = v1 != v2 ? 1l : 0l; break; } if (doubleValue != null) { return FloatingPointValue.create(doubleValue); } else if (longValue != null) { return IntegralValue.create(longValue); } else { return IntegralValue.UNKNOWN; } } private static IntegralValue applyBinaryOperator(final int op, final long v1, final long v2) { Long value = null; switch (op) { case IASTBinaryExpression.op_multiply: value = v1 * v2; break; case IASTBinaryExpression.op_divide: if (v2 != 0) { value = v1 / v2; } break; case IASTBinaryExpression.op_modulo: if (v2 != 0) { value = v1 % v2; } break; case IASTBinaryExpression.op_plus: value = v1 + v2; break; case IASTBinaryExpression.op_minus: value = v1 - v2; break; case IASTBinaryExpression.op_shiftLeft: value = v1 << v2; break; case IASTBinaryExpression.op_shiftRight: value = v1 >> v2; break; case IASTBinaryExpression.op_lessThan: value = v1 < v2 ? 1l : 0l; break; case IASTBinaryExpression.op_greaterThan: value = v1 > v2 ? 1l : 0l; break; case IASTBinaryExpression.op_lessEqual: value = v1 <= v2 ? 1l : 0l; break; case IASTBinaryExpression.op_greaterEqual: value = v1 >= v2 ? 1l : 0l; break; case IASTBinaryExpression.op_binaryAnd: value = v1 & v2; break; case IASTBinaryExpression.op_binaryXor: value = v1 ^ v2; break; case IASTBinaryExpression.op_binaryOr: value = v1 | v2; break; case IASTBinaryExpression.op_logicalAnd: value = v1 != 0 && v2 != 0 ? 1l : 0l; break; case IASTBinaryExpression.op_logicalOr: value = v1 != 0 || v2 != 0 ? 1l : 0l; break; case IASTBinaryExpression.op_equals: value = v1 == v2 ? 1l : 0l; break; case IASTBinaryExpression.op_notequals: value = v1 != v2 ? 1l : 0l; break; case IASTBinaryExpression.op_max: value = Math.max(v1, v2); break; case IASTBinaryExpression.op_min: value = Math.min(v1, v2); break; } if (value != null) { return IntegralValue.create(value); } else { return IntegralValue.UNKNOWN; } } public static IValue evaluateUnaryTypeIdExpression(int operator, IType type, IASTNode point) { IValue val = applyUnaryTypeIdOperator(operator, type, point); if (isInvalidValue(val)) return IntegralValue.UNKNOWN; return val; } public static IValue evaluateBinaryTypeIdExpression(IASTBinaryTypeIdExpression.Operator operator, IType type1, IType type2, IASTNode point) { IValue val = applyBinaryTypeIdOperator(operator, type1, type2, point); if (isInvalidValue(val)) return IntegralValue.UNKNOWN; return val; } /** * Computes the canonical representation of the value of the expression. */ private static IValue evaluate(IASTExpression exp) { // Some C++ expression types can involve evaluating functions. // For these, the value will be computed based on the evaluation. if (exp instanceof ICPPASTFunctionCallExpression || exp instanceof ICPPASTSimpleTypeConstructorExpression || exp instanceof ICPPASTUnaryExpression || exp instanceof ICPPASTBinaryExpression) { return null; } if (exp == null) return IntegralValue.UNKNOWN; if (exp instanceof IASTArraySubscriptExpression) { return IntegralValue.UNKNOWN; } if (exp instanceof IASTBinaryExpression) { return evaluateBinaryExpression((IASTBinaryExpression) exp); } if (exp instanceof IASTCastExpression) { // must be ahead of unary return evaluate(((IASTCastExpression) exp).getOperand()); } if (exp instanceof IASTUnaryExpression) { return evaluateUnaryExpression((IASTUnaryExpression) exp); } if (exp instanceof IASTConditionalExpression) { IASTConditionalExpression cexpr= (IASTConditionalExpression) exp; IValue v= evaluate(cexpr.getLogicalConditionExpression()); if (isInvalidValue(v)) return v; if (isDeferredValue(v)) return null; // the value will be computed using the evaluation if (v.numberValue().longValue() == 0) { return evaluate(cexpr.getNegativeResultExpression()); } final IASTExpression pe = cexpr.getPositiveResultExpression(); if (pe == null) // gnu-extension allows to omit the positive expression. return v; return evaluate(pe); } if (exp instanceof IASTIdExpression) { IBinding b= ((IASTIdExpression) exp).getName().resolvePreBinding(); return evaluateBinding(b); } if (exp instanceof IASTLiteralExpression) { IASTLiteralExpression litEx= (IASTLiteralExpression) exp; switch (litEx.getKind()) { case IASTLiteralExpression.lk_false: case IASTLiteralExpression.lk_nullptr: return IntegralValue.create(0); case IASTLiteralExpression.lk_true: return IntegralValue.create(1); case IASTLiteralExpression.lk_integer_constant: try { return IntegralValue.create(ExpressionEvaluator.getNumber(litEx.getValue())); } catch (EvalException e) { return IntegralValue.UNKNOWN; } case IASTLiteralExpression.lk_char_constant: try { final char[] image= litEx.getValue(); if (image.length > 1 && image[0] == 'L') return IntegralValue.create(ExpressionEvaluator.getChar(image, 2)); return IntegralValue.create(ExpressionEvaluator.getChar(image, 1)); } catch (EvalException e) { return IntegralValue.UNKNOWN; } case IASTLiteralExpression.lk_float_constant: return FloatingPointValue.create(litEx.getValue()); case IASTLiteralExpression.lk_string_literal: return CStringValue.create(litEx.getValue()); } } if (exp instanceof IASTTypeIdExpression) { IASTTypeIdExpression typeIdExp = (IASTTypeIdExpression) exp; ASTTranslationUnit ast = (ASTTranslationUnit) exp.getTranslationUnit(); final IType type = ast.createType(typeIdExp.getTypeId()); if (type instanceof ICPPUnknownType) return null; return applyUnaryTypeIdOperator(typeIdExp.getOperator(), type, exp); } if (exp instanceof IASTBinaryTypeIdExpression) { IASTBinaryTypeIdExpression typeIdExp = (IASTBinaryTypeIdExpression) exp; ASTTranslationUnit ast = (ASTTranslationUnit) exp.getTranslationUnit(); IType t1= ast.createType(typeIdExp.getOperand1()); IType t2= ast.createType(typeIdExp.getOperand2()); if (CPPTemplates.isDependentType(t1) || CPPTemplates.isDependentType(t2)) return null; return applyBinaryTypeIdOperator(typeIdExp.getOperator(), t1, t2, exp); } return IntegralValue.UNKNOWN; } /** * Extract a value off a binding. */ private static IValue evaluateBinding(IBinding b) { if (b instanceof IType) { return IntegralValue.UNKNOWN; } if (b instanceof ICPPTemplateNonTypeParameter) { return null; } if (b instanceof ICPPUnknownBinding) { return null; } IValue value= null; if (b instanceof IVariable) { value= ((IVariable) b).getInitialValue(); } else if (b instanceof IEnumerator) { value= ((IEnumerator) b).getValue(); } if (isInvalidValue(value)) { return IntegralValue.UNKNOWN; } return value; } private static IValue applyUnaryTypeIdOperator(int operator, IType type, IASTNode point) { switch (operator) { case op_sizeof: return getSize(type, point); case op_alignof: return getAlignment(type, point); case op_typeid: break; case op_has_nothrow_copy: break; // TODO(sprigogin): Implement case op_has_nothrow_constructor: break; // TODO(sprigogin): Implement case op_has_trivial_assign: break; // TODO(sprigogin): Implement case op_has_trivial_constructor: break; // TODO(sprigogin): Implement case op_has_trivial_copy: return IntegralValue.create(!(type instanceof ICPPClassType) || TypeTraits.hasTrivialCopyCtor((ICPPClassType) type, point) ? 1 : 0); case op_has_trivial_destructor: break; // TODO(sprigogin): Implement case op_has_virtual_destructor: break; // TODO(sprigogin): Implement case op_is_abstract: return IntegralValue.create(type instanceof ICPPClassType && TypeTraits.isAbstract((ICPPClassType) type, point) ? 1 : 0); case op_is_class: return IntegralValue.create(type instanceof ICompositeType && ((ICompositeType) type).getKey() != ICompositeType.k_union ? 1 : 0); case op_is_empty: return IntegralValue.create(TypeTraits.isEmpty(type, point) ? 1 : 0); case op_is_enum: return IntegralValue.create(type instanceof IEnumeration ? 1 : 0); case op_is_final: return IntegralValue.create(type instanceof ICPPClassType && ((ICPPClassType) type).isFinal() ? 1 : 0); case op_is_literal_type: break; // TODO(sprigogin): Implement case op_is_pod: return IntegralValue.create(TypeTraits.isPOD(type, point) ? 1 : 0); case op_is_polymorphic: return IntegralValue.create(type instanceof ICPPClassType && TypeTraits.isPolymorphic((ICPPClassType) type, point) ? 1 : 0); case op_is_standard_layout: return IntegralValue.create(TypeTraits.isStandardLayout(type, point) ? 1 : 0); case op_is_trivial: return IntegralValue.create(type instanceof ICPPClassType && TypeTraits.isTrivial((ICPPClassType) type, point) ? 1 : 0); case op_is_trivially_copyable: return IntegralValue.create(TypeTraits.isTriviallyCopyable(type, point) ? 1 : 0); case op_is_union: return IntegralValue.create(type instanceof ICompositeType && ((ICompositeType) type).getKey() == ICompositeType.k_union ? 1 : 0); case op_typeof: break; } return IntegralValue.UNKNOWN; } private static IValue getAlignment(IType type, IASTNode point) { SizeAndAlignment sizeAndAlignment = SizeofCalculator.getSizeAndAlignment(type, point); if (sizeAndAlignment == null) return IntegralValue.UNKNOWN; return IntegralValue.create(sizeAndAlignment.alignment); } private static IValue getSize(IType type, IASTNode point) { SizeAndAlignment sizeAndAlignment = SizeofCalculator.getSizeAndAlignment(type, point); if (sizeAndAlignment == null) return IntegralValue.UNKNOWN; return IntegralValue.create(sizeAndAlignment.size); } private static IValue evaluateUnaryExpression(IASTUnaryExpression exp) { final int unaryOp= exp.getOperator(); if (unaryOp == IASTUnaryExpression.op_sizeof) { final IASTExpression operand = exp.getOperand(); if (operand != null) { IType type = operand.getExpressionType(); if (type instanceof ICPPUnknownType) return null; ASTTranslationUnit ast = (ASTTranslationUnit) exp.getTranslationUnit(); SizeofCalculator calculator = ast.getSizeofCalculator(); SizeAndAlignment info = calculator.sizeAndAlignment(type); if (info != null) return IntegralValue.create(info.size); } return IntegralValue.UNKNOWN; } if (unaryOp == IASTUnaryExpression.op_amper || unaryOp == IASTUnaryExpression.op_star || unaryOp == IASTUnaryExpression.op_sizeofParameterPack) { return IntegralValue.UNKNOWN; } final IValue value= evaluate(exp.getOperand()); if (isInvalidValue(value)) return value; if (isDeferredValue(value)) return null; // the value will be computed using the evaluation return applyUnaryOperator(unaryOp, value); } private static IValue applyUnaryOperator(final int unaryOp, final IValue value) { if (isInvalidValue(value) || value.numberValue() == null) { return IntegralValue.UNKNOWN; } if (!(value instanceof IntegralValue) && !(value instanceof FloatingPointValue)) { return IntegralValue.UNKNOWN; } switch (unaryOp) { case IASTUnaryExpression.op_bracketedPrimary: case IASTUnaryExpression.op_plus: return value; case IASTUnaryExpression.op_prefixIncr: case IASTUnaryExpression.op_postFixIncr: if (value instanceof IntegralValue) { return IntegralValue.create(value.numberValue().longValue() + 1); } else { FloatingPointValue fpv = (FloatingPointValue) value; return FloatingPointValue.create(fpv.numberValue().doubleValue() + 1); } case IASTUnaryExpression.op_prefixDecr: case IASTUnaryExpression.op_postFixDecr: if (value instanceof IntegralValue) { return IntegralValue.create(value.numberValue().longValue() - 1); } else { FloatingPointValue fpv = (FloatingPointValue) value; return FloatingPointValue.create(fpv.numberValue().doubleValue() - 1); } case IASTUnaryExpression.op_minus: if (value instanceof IntegralValue) { return IntegralValue.create(-value.numberValue().longValue()); } else { FloatingPointValue fpv = (FloatingPointValue) value; return FloatingPointValue.create(-fpv.numberValue().doubleValue()); } case IASTUnaryExpression.op_tilde: if (value instanceof IntegralValue) { return IntegralValue.create(~value.numberValue().longValue()); } else { return IntegralValue.UNKNOWN; } case IASTUnaryExpression.op_not: if (value instanceof IntegralValue) { Long num = value.numberValue().longValue(); return IntegralValue.create(num == 0 ? 1 : 0); } else { FloatingPointValue fpv = (FloatingPointValue) value; Double num = fpv.numberValue().doubleValue(); return IntegralValue.create(num == 0 ? 1 : 0); } } return IntegralValue.UNKNOWN; } private static IValue evaluateBinaryExpression(IASTBinaryExpression exp) { final int op= exp.getOperator(); // Optimization: if the operator is == or != and the AST nodes // themselves are equal, we know the answer without having to // do any evaluation. if (op == IASTBinaryExpression.op_equals && exp.getOperand1().equals(exp.getOperand2())) { return IntegralValue.create(true); } if (op == IASTBinaryExpression.op_notequals && exp.getOperand1().equals(exp.getOperand2())) { return IntegralValue.create(false); } final IValue o1= evaluate(exp.getOperand1()); if (isInvalidValue(o1)) return o1; final IValue o2= evaluate(exp.getOperand2()); if (isInvalidValue(o2)) return o2; if (isDeferredValue(o1) || isDeferredValue(o2)) return null; // the value will be computed using the evaluation return evaluateBinaryExpression(op, o1, o2); } private static IValue applyBinaryTypeIdOperator(IASTBinaryTypeIdExpression.Operator operator, IType type1, IType type2, IASTNode point) { switch (operator) { case __is_base_of: type1 = SemanticUtil.getNestedType(type1, TDEF); type2 = SemanticUtil.getNestedType(type2, TDEF); if (type1 instanceof ICPPClassType && type2 instanceof ICPPClassType && (type1.isSameType(type2) || ClassTypeHelper.isSubclass((ICPPClassType) type2, (ICPPClassType) type1, point))) { return IntegralValue.create(1); } return IntegralValue.create(0); case __is_trivially_assignable: return IntegralValue.UNKNOWN; // TODO: Implement. } return IntegralValue.UNKNOWN; } private static boolean isInvalidValue(IValue value) { return value == null || value == IntegralValue.UNKNOWN || value == IntegralValue.ERROR; } private static boolean isDeferredValue(IValue value) { return value instanceof DependentValue || (value instanceof IntegralValue && ((IntegralValue) value).numberValue() == null); } /** * Returns the numerical value of the given expression if the expression can be evaluated * at compile time. * * @param expr the expression to evaluate * @return the numerical value of the expression, or {@code null} if the expression cannot be evaluated * to a constant */ public static Number getConstantNumericalValue(IASTExpression expr) { IValue val = evaluate(expr); if (val != null) { return val.numberValue(); } if (expr instanceof ICPPEvaluationOwner) { ICPPEvaluation eval = ((ICPPEvaluationOwner) expr).getEvaluation(); if (eval.isConstantExpression(expr) && !eval.isValueDependent()) return eval.getValue(expr).numberValue(); } return null; } }