/*******************************************************************************
* Copyright (c) 2004, 2010 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:
* Andrew Niefer (IBM Corporation) - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Ed Swartz (Nokia)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.DOMException;
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.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IPointerType;
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.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IInternalVariable;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.core.runtime.PlatformObject;
public class CPPVariable extends PlatformObject implements ICPPVariable, ICPPInternalBinding, IInternalVariable {
private IASTName fDefinition = null;
private IASTName fDeclarations[] = null;
private IType fType = null;
private boolean fAllResolved;
public CPPVariable(IASTName name) {
boolean isDef = name == null ? false : name.isDefinition();
if (name instanceof ICPPASTQualifiedName) {
IASTName[] ns = ((ICPPASTQualifiedName)name).getNames();
name = ns[ns.length - 1];
}
if (isDef)
fDefinition = name;
else
fDeclarations = new IASTName[] { name };
// built-in variables supply a null
if (name != null) {
name.setBinding(this);
} else {
assert this instanceof CPPBuiltinVariable;
}
}
private IASTDeclarator findDeclarator(IASTName name) {
IASTNode node = name.getParent();
if (node instanceof ICPPASTQualifiedName)
node = node.getParent();
if (!(node instanceof IASTDeclarator))
return null;
IASTDeclarator dtor = (IASTDeclarator) node;
while (dtor.getParent() instanceof IASTDeclarator)
dtor = (IASTDeclarator) dtor.getParent();
return dtor;
}
public void addDeclaration(IASTNode node) {
if (!(node instanceof IASTName))
return;
IASTName name = (IASTName) node;
if (fDefinition == null && name.isDefinition()) {
fDefinition = name;
} else if (fDeclarations == null) {
fDeclarations = new IASTName[] { name };
} else {
// keep the lowest offset declaration at the first position
if (fDeclarations.length > 0
&& ((ASTNode) node).getOffset() < ((ASTNode) fDeclarations[0]).getOffset()) {
fDeclarations = (IASTName[]) ArrayUtil.prepend(IASTName.class, fDeclarations, name);
} else {
fDeclarations = (IASTName[]) ArrayUtil.append(IASTName.class, fDeclarations, name);
}
}
// array types may be incomplete
if (fType instanceof IArrayType) {
fType = null;
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPBinding#getDeclarations()
*/
public IASTNode[] getDeclarations() {
return fDeclarations;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPBinding#getDefinition()
*/
public IASTNode getDefinition() {
return fDefinition;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IVariable#getType()
*/
public IType getType() {
if (fType != null) {
return fType;
}
IArrayType firstCandidate= null;
final int length = fDeclarations == null ? 0 : fDeclarations.length;
for (int i = -1; i < length; i++) {
IASTName n = i==-1 ? fDefinition : fDeclarations[i];
if (n != null) {
while (n.getParent() instanceof IASTName)
n = (IASTName) n.getParent();
IASTNode node = n.getParent();
if (node instanceof IASTDeclarator) {
IType t= CPPVisitor.createType((IASTDeclarator) node);
if (t instanceof IArrayType && ((IArrayType) t).getSize() == null) {
if (firstCandidate == null) {
firstCandidate= (IArrayType) t;
}
} else {
return fType= t;
}
}
}
}
fType= firstCandidate;
if (!fAllResolved) {
resolveAllDeclarations();
return getType();
}
return fType;
}
private void resolveAllDeclarations() {
if (fAllResolved)
return;
fAllResolved= true;
final int length = fDeclarations == null ? 0 : fDeclarations.length;
for (int i = -1; i < length; i++) {
IASTName n = i==-1 ? fDefinition : fDeclarations[i];
if (n != null) {
IASTTranslationUnit tu = n.getTranslationUnit();
if (tu != null) {
CPPVisitor.getDeclarations(tu, this);
return;
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IBinding#getName()
*/
public String getName() {
return new String(getNameCharArray());
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IBinding#getNameCharArray()
*/
public char[] getNameCharArray() {
if (fDeclarations != null) {
return fDeclarations[0].getSimpleID();
}
return fDefinition.getSimpleID();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IBinding#getScope()
*/
public IScope getScope() {
return CPPVisitor.getContainingScope(fDefinition != null ? fDefinition : fDeclarations[0]);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IBinding#getFullyQualifiedName()
*/
public String[] getQualifiedName() {
return CPPVisitor.getQualifiedName(this);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IBinding#getFullyQualifiedNameCharArray()
*/
public char[][] getQualifiedNameCharArray() {
return CPPVisitor.getQualifiedNameCharArray(this);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding#isGloballyQualified()
*/
public boolean isGloballyQualified() throws DOMException {
IScope scope = getScope();
while (scope != null) {
if (scope instanceof ICPPBlockScope)
return false;
scope = scope.getParent();
}
return true;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding#addDefinition(org.eclipse.cdt.core.dom.ast.IASTNode)
*/
public void addDefinition(IASTNode node) {
addDeclaration(node);
}
public boolean hasStorageClass(int storage) {
IASTName name = (IASTName) getDefinition();
IASTNode[] ns = getDeclarations();
int i = -1;
do {
if (name != null) {
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;
}
}
}
if (ns != null && ++i < ns.length)
name = (IASTName) ns[i];
else
break;
} while (name != null);
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable#isMutable()
*/
public boolean isMutable() {
//7.1.1-8 the mutable specifier can only be applied to names of class data members
return false;
}
public boolean isStatic() {
return hasStorageClass(IASTDeclSpecifier.sc_static);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IVariable#isExtern()
*/
public boolean isExtern() {
return hasStorageClass(IASTDeclSpecifier.sc_extern);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IVariable#isExtern()
*/
public boolean isExternC() {
if (CPPVisitor.isExternC(getDefinition())) {
return true;
}
IASTNode[] ds= getDeclarations();
if (ds != null) {
for (IASTNode element : ds) {
if (CPPVisitor.isExternC(element)) {
return true;
}
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IVariable#isAuto()
*/
public boolean isAuto() {
return hasStorageClass(IASTDeclSpecifier.sc_auto);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IVariable#isRegister()
*/
public boolean isRegister() {
return hasStorageClass(IASTDeclSpecifier.sc_register);
}
public ILinkage getLinkage() {
return Linkage.CPP_LINKAGE;
}
public IBinding getOwner() {
IASTName node = fDefinition != null ? fDefinition : fDeclarations[0];
return CPPVisitor.findNameOwner(node, !hasStorageClass(IASTDeclSpecifier.sc_extern));
}
@Override
public String toString() {
return getName();
}
public IValue getInitialValue() {
return getInitialValue(Value.MAX_RECURSION_DEPTH);
}
public IValue getInitialValue(int maxDepth) {
if (fDefinition != null) {
final IValue val= getInitialValue(fDefinition, maxDepth);
if (val != null)
return val;
}
if (fDeclarations != null) {
for (IASTName decl : fDeclarations) {
if (decl == null)
break;
final IValue val= getInitialValue(decl, maxDepth);
if (val != null)
return val;
}
}
return null;
}
private IValue getInitialValue(IASTName name, int maxDepth) {
IASTDeclarator dtor= findDeclarator(name);
if (dtor != null) {
IASTInitializer init= dtor.getInitializer();
if (init != null) {
IASTInitializerClause clause= null;
if (init instanceof IASTEqualsInitializer) {
clause= ((IASTEqualsInitializer) init).getInitializerClause();
} else if (init instanceof ICPPASTConstructorInitializer) {
IASTInitializerClause[] args= ((ICPPASTConstructorInitializer) init).getArguments();
if (args.length == 1 && args[0] instanceof IASTExpression) {
IType type= SemanticUtil.getUltimateTypeUptoPointers(getType());
if (type instanceof IPointerType || type instanceof IBasicType) {
clause= args[0];
}
}
} else if (init instanceof ICPPASTInitializerList) {
ICPPASTInitializerList list= (ICPPASTInitializerList) init;
switch (list.getSize()) {
case 0:
return Value.create(0);
case 1:
clause= list.getClauses()[0];
}
}
if (clause instanceof IASTExpression) {
return Value.create((IASTExpression) clause, maxDepth);
}
return Value.UNKNOWN;
}
}
return null;
}
}