blob: 42ceb897792cfad7e75fcab82e61ef7b5a36bb95 [file] [log] [blame]
/*******************************************************************************
* 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 ASTAttributeOwner 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;
}
}