/*******************************************************************************
* Copyright (c) 2005, 2014 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:
* IBM Rational Software - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
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.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.ValueFactory;
import org.eclipse.core.runtime.PlatformObject;
/**
* Binding for a global or a local variable, serves as base class for fields.
*/
public class CVariable extends PlatformObject implements ICInternalBinding, IVariable {
private IASTName[] declarations = null;
private IType type = null;
/**
* The set of CVariable objects for which initial value computation is in progress on each thread.
* This is used to guard against recursion during initial value computation.
*/
private static final ThreadLocal<Set<CVariable>> fInitialValueInProgress = new ThreadLocal<Set<CVariable>>() {
@Override
protected Set<CVariable> initialValue() {
return new HashSet<>();
}
};
public CVariable(IASTName name) {
declarations = new IASTName[] { name };
}
@Override
public IASTNode getPhysicalNode() {
return declarations[0];
}
public void addDeclaration(IASTName name) {
if (name != null && name.isActive()) {
declarations = ArrayUtil.append(IASTName.class, declarations, name);
}
}
@Override
public IType getType() {
if (type == null && declarations[0].getParent() instanceof IASTDeclarator)
type = CVisitor.createType((IASTDeclarator) declarations[0].getParent());
return type;
}
@Override
public String getName() {
return declarations[0].toString();
}
@Override
public char[] getNameCharArray() {
return declarations[0].toCharArray();
}
@Override
public IScope getScope() {
IASTDeclarator declarator = (IASTDeclarator) declarations[0].getParent();
return CVisitor.getContainingScope(declarator.getParent());
}
@Override
public boolean isStatic() {
return hasStorageClass(IASTDeclSpecifier.sc_static);
}
public boolean hasStorageClass(int storage) {
if (declarations == null)
return false;
for (int i = 0; i < declarations.length && declarations[i] != null; i++) {
final IASTName name = declarations[i];
IASTNode parent = name.getParent();
while (!(parent instanceof IASTDeclaration))
parent = parent.getParent();
if (parent instanceof IASTSimpleDeclaration) {
IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier();
if (declSpec.getStorageClass() == storage) {
return true;
}
}
}
return false;
}
@Override
public boolean isExtern() {
return hasStorageClass(IASTDeclSpecifier.sc_extern);
}
@Override
public boolean isAuto() {
return hasStorageClass(IASTDeclSpecifier.sc_auto);
}
@Override
public boolean isRegister() {
return hasStorageClass(IASTDeclSpecifier.sc_register);
}
@Override
public ILinkage getLinkage() {
return Linkage.C_LINKAGE;
}
@Override
public IASTNode[] getDeclarations() {
return declarations;
}
@Override
public IASTNode getDefinition() {
return getPhysicalNode();
}
@Override
public IBinding getOwner() {
if (declarations == null || declarations.length == 0)
return null;
return CVisitor.findDeclarationOwner(declarations[0], true);
}
@Override
public IValue getInitialValue() {
Set<CVariable> recursionProtectionSet = fInitialValueInProgress.get();
if (!recursionProtectionSet.add(this)) {
return IntegralValue.UNKNOWN;
}
try {
if (declarations != null) {
for (IASTName decl : declarations) {
if (decl == null)
break;
final IValue val = getInitialValue(decl);
if (val != null)
return val;
}
}
} finally {
recursionProtectionSet.remove(this);
}
return null;
}
private IValue getInitialValue(IASTName name) {
IASTDeclarator dtor = findDeclarator(name);
if (dtor != null) {
IASTInitializer init = dtor.getInitializer();
if (init instanceof IASTEqualsInitializer) {
final IASTInitializerClause initClause = ((IASTEqualsInitializer) init)
.getInitializerClause();
if (initClause instanceof IASTExpression) {
return ValueFactory.create((IASTExpression) initClause);
}
}
if (init != null)
return IntegralValue.UNKNOWN;
}
return null;
}
private IASTDeclarator findDeclarator(IASTName name) {
IASTNode node = name.getParent();
if (!(node instanceof IASTDeclarator))
return null;
return ASTQueries.findOutermostDeclarator((IASTDeclarator) node);
}
@Override
public String toString() {
return getName();
}
}