/******************************************************************************* * 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 org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumerator; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; /** * Base class for C and C++ enumerators. */ public abstract class ASTEnumerator extends ASTNode implements IASTEnumerator, IASTAmbiguityParent { private IASTName name; private IASTExpression value; private IValue integralValue; public ASTEnumerator() { } public ASTEnumerator(IASTName name, IASTExpression value) { setName(name); setValue(value); } protected <T extends ASTEnumerator> T copy(T copy, CopyStyle style) { copy.setName(name == null ? null : name.copy(style)); copy.setValue(value == null ? null : value.copy(style)); return super.copy(copy, style); } @Override public void setName(IASTName name) { assertNotFrozen(); this.name = name; if (name != null) { name.setParent(this); name.setPropertyInParent(ENUMERATOR_NAME); } } @Override public IASTName getName() { return name; } @Override public void setValue(IASTExpression expression) { assertNotFrozen(); this.value = expression; if (expression != null) { expression.setParent(this); expression.setPropertyInParent(ENUMERATOR_VALUE); } } @Override public IASTExpression getValue() { return value; } @Override public boolean accept(ASTVisitor action) { if (action.shouldVisitEnumerators) { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; } } if (name != null && !name.accept(action)) return false; if (value != null && !value.accept(action)) return false; if (action.shouldVisitEnumerators) { switch (action.leave(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; } } return true; } @Override public int getRoleForName(IASTName n) { if (n == name) return r_definition; return r_reference; } @Override public void replace(IASTNode child, IASTNode other) { if (child == value) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); value = (IASTExpression) other; } } public IValue getIntegralValue() { if (integralValue == null) { IASTNode parent= getParent(); if (parent instanceof IASTInternalEnumerationSpecifier) { IASTInternalEnumerationSpecifier enumeration= (IASTInternalEnumerationSpecifier) parent; if (enumeration.startValueComputation()) { // Prevent infinite recursion. computeEnumValues(enumeration); } } if (integralValue == null) { integralValue= IntegralValue.UNKNOWN; } } return integralValue; } private static void computeEnumValues(IASTInternalEnumerationSpecifier enumeration) { try { IType fixedType = null; if (enumeration instanceof ICPPASTEnumerationSpecifier) { IBinding binding = enumeration.getName().resolveBinding(); if (binding instanceof ICPPEnumeration) { fixedType = ((ICPPEnumeration) binding).getFixedType(); } } IType type = fixedType == null ? CPPBasicType.INT : null; IValue previousExplicitValue = null; int delta = 0; IASTEnumerator[] etors= enumeration.getEnumerators(); for (IASTEnumerator etor : etors) { IBinding etorBinding = etor.getName().resolveBinding(); IValue val; IASTExpression expr= etor.getValue(); if (expr != null) { val= ValueFactory.create(expr); previousExplicitValue = val; delta = 1; if (fixedType == null) { type = expr.getExpressionType(); type = SemanticUtil.getNestedType(type, SemanticUtil.CVTYPE | SemanticUtil.TDEF); if (etorBinding instanceof CPPEnumerator) { ((CPPEnumerator) etorBinding).setInternalType(type); } } } else { if (previousExplicitValue != null) { val = IntegralValue.incrementedValue(previousExplicitValue, delta); } else { val = IntegralValue.create(delta); } delta++; if (fixedType == null && type instanceof IBasicType) { type = getTypeOfIncrementedValue((IBasicType) type, val); if (etorBinding instanceof CPPEnumerator) { ((CPPEnumerator) etorBinding).setInternalType(type); } } } if (etor instanceof ASTEnumerator) { ((ASTEnumerator) etor).integralValue= val; } } } finally { enumeration.finishValueComputation(); } } /** * [dcl.enum] 7.2-5: * "... the type of the initializing value is the same as the type of the initializing value of * the preceding enumerator unless the incremented value is not representable in that type, in * which case the type is an unspecified integral type sufficient to contain the incremented * value. If no such type exists, the program is ill-formed." * * @param type the type of the previous value * @param val the incremented value * @return the type of the incremented value */ public static IBasicType getTypeOfIncrementedValue(IBasicType type, IValue val) { Number numericalValue = val.numberValue(); if (numericalValue != null) { long longValue = numericalValue.longValue(); if ((type.getKind() != Kind.eInt && type.getKind() != Kind.eInt128) || type.isShort()) { type = type.isUnsigned() ? CPPBasicType.UNSIGNED_INT : CPPBasicType.INT; } if (!ArithmeticConversion.fitsIntoType(type, longValue)) { if (!type.isUnsigned()) { if (type.getKind() != Kind.eInt128) { if (type.isLongLong()) { type = CPPBasicType.UNSIGNED_INT128; } else if (type.isLong()) { type = CPPBasicType.UNSIGNED_LONG_LONG; } else { type = CPPBasicType.UNSIGNED_LONG; } } } else { if (type.getKind() == Kind.eInt128) { if (longValue >= 0) { type = CPPBasicType.UNSIGNED_INT128; } } else { if (type.isLongLong()) { type = CPPBasicType.INT128; } else if (type.isLong()) { type = CPPBasicType.LONG_LONG; } else { type = CPPBasicType.LONG; } } } } } return type; } }