/*******************************************************************************
* 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:
* IBM Rational Software - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
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.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IParameter;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.core.runtime.PlatformObject;
/**
* Represents a function.
*/
public class CFunction extends PlatformObject implements IFunction, ICInternalFunction {
private IASTDeclarator[] declarators = null;
private IASTFunctionDeclarator definition;
private static final int FULLY_RESOLVED = 1;
private static final int RESOLUTION_IN_PROGRESS = 1 << 1;
private int bits = 0;
protected IFunctionType type = null;
public CFunction(IASTDeclarator declarator) {
storeDeclarator(declarator);
}
private void storeDeclarator(IASTDeclarator declarator) {
if (declarator != null) {
if (declarator instanceof ICASTKnRFunctionDeclarator) {
definition = (IASTFunctionDeclarator) declarator;
} else if (declarator instanceof IASTFunctionDeclarator
&& ASTQueries.findOutermostDeclarator(declarator).getParent() instanceof IASTFunctionDefinition) {
definition = (IASTFunctionDeclarator) declarator;
} else {
declarators = (IASTDeclarator[]) ArrayUtil.append(IASTDeclarator.class, declarators, declarator);
}
}
}
public IASTDeclarator getPhysicalNode() {
if (definition != null)
return definition;
else if (declarators != null && declarators.length > 0)
return declarators[0];
return null;
}
public void addDeclarator(IASTDeclarator fnDeclarator) {
if (!fnDeclarator.isActive())
return;
if (fnDeclarator instanceof IASTFunctionDeclarator) {
updateParameterBindings((IASTFunctionDeclarator) fnDeclarator);
}
storeDeclarator(fnDeclarator);
}
protected IASTTranslationUnit getTranslationUnit() {
if( definition != null )
return definition.getTranslationUnit();
else if( declarators != null )
return declarators[0].getTranslationUnit();
return null;
}
private void resolveAllDeclarations(){
if( (bits & (FULLY_RESOLVED | RESOLUTION_IN_PROGRESS)) == 0 ){
bits |= RESOLUTION_IN_PROGRESS;
IASTTranslationUnit tu = getTranslationUnit();
if( tu != null ){
CVisitor.getDeclarations( tu, this );
}
declarators = (IASTDeclarator[]) ArrayUtil.trim(IASTDeclarator.class, declarators);
bits |= FULLY_RESOLVED;
bits &= ~RESOLUTION_IN_PROGRESS;
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IFunction#getParameters()
*/
public IParameter[] getParameters() {
int j=-1;
int len = declarators != null ? declarators.length : 0;
for (IASTDeclarator dtor = definition; j < len; j++) {
if (j >= 0) {
dtor = declarators[j];
}
if (dtor instanceof IASTStandardFunctionDeclarator) {
IASTParameterDeclaration[] params = ((IASTStandardFunctionDeclarator) dtor).getParameters();
int size = params.length;
IParameter[] result = new IParameter[size];
if (size > 0) {
for (int i = 0; i < size; i++) {
IASTParameterDeclaration p = params[i];
result[i] = (IParameter) ASTQueries.findInnermostDeclarator(p.getDeclarator())
.getName().resolveBinding();
}
}
return result;
}
if (dtor instanceof ICASTKnRFunctionDeclarator) {
IASTName[] names = ((ICASTKnRFunctionDeclarator) dtor).getParameterNames();
IParameter[] result = new IParameter[names.length];
if (names.length > 0) {
// Ensures that the list of parameters is created in the same order as the K&R C parameter
// names
for (int i = 0; i < names.length; i++) {
IASTDeclarator decl = CVisitor.getKnRParameterDeclarator(
(ICASTKnRFunctionDeclarator) dtor, names[i]);
if (decl != null) {
result[i] = (IParameter) decl.getName().resolveBinding();
} else {
result[i] = new CParameter.CParameterProblem(names[i],
IProblemBinding.SEMANTIC_KNR_PARAMETER_DECLARATION_NOT_FOUND, names[i]
.toCharArray());
}
}
}
return result;
}
}
if ((bits & (FULLY_RESOLVED | RESOLUTION_IN_PROGRESS)) == 0) {
resolveAllDeclarations();
return getParameters();
}
return CBuiltinParameter.createParameterList(getType());
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IBinding#getName()
*/
public String getName() {
return getASTName().toString();
}
public char[] getNameCharArray(){
return getASTName().toCharArray();
}
private IASTName getASTName() {
return ASTQueries.findInnermostDeclarator(getPhysicalNode()).getName();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IBinding#getScope()
*/
public IScope getScope() {
IASTDeclarator dtor = getPhysicalNode();
if (dtor != null)
return CVisitor.getContainingScope(ASTQueries.findOutermostDeclarator(dtor).getParent());
return null;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IFunction#getFunctionScope()
*/
public IScope getFunctionScope() {
if (definition != null) {
IASTFunctionDefinition def = (IASTFunctionDefinition) definition.getParent();
return def.getScope();
}
return null;
}
public IFunctionType getType() {
if (type == null) {
type = createType();
}
return type;
}
protected IFunctionType createType() {
IASTDeclarator declarator = getPhysicalNode();
if (declarator == null && (bits & FULLY_RESOLVED) == 0) {
resolveAllDeclarations();
declarator = getPhysicalNode();
}
if (declarator != null) {
IType tempType = CVisitor.unwrapTypedefs(CVisitor.createType(declarator));
if (tempType instanceof IFunctionType)
return (IFunctionType) tempType;
}
return null;
}
public IBinding resolveParameter( IASTName paramName ){
if( paramName.getBinding() != null )
return paramName.getBinding();
IBinding binding = null;
int idx = 0;
IASTNode parent = paramName.getParent();
while( parent instanceof IASTDeclarator && !(parent instanceof ICASTKnRFunctionDeclarator ) )
parent = parent.getParent();
ICASTKnRFunctionDeclarator fKnRDtor = null;
IASTDeclarator knrParamDtor = null;
if( parent instanceof IASTParameterDeclaration ){
IASTStandardFunctionDeclarator fdtor = (IASTStandardFunctionDeclarator) parent.getParent();
IASTParameterDeclaration [] ps = fdtor.getParameters();
for( ; idx < ps.length; idx++ ){
if( parent == ps[idx] )
break;
}
} else if( parent instanceof IASTSimpleDeclaration ){
//KnR: name in declaration list
fKnRDtor = (ICASTKnRFunctionDeclarator) parent.getParent();
IASTName [] ps = fKnRDtor.getParameterNames();
char [] n = paramName.toCharArray();
for( ; idx < ps.length; idx++ ){
if( CharArrayUtils.equals( ps[idx].toCharArray(), n ) )
break;
}
} else {
//KnR: name in name list
fKnRDtor = (ICASTKnRFunctionDeclarator) parent;
IASTName [] ps = fKnRDtor.getParameterNames();
for( ; idx < ps.length; idx++ ){
if( ps[idx] == paramName)
break;
}
knrParamDtor = CVisitor.getKnRParameterDeclarator( fKnRDtor, paramName );
if( knrParamDtor != null )
paramName = knrParamDtor.getName();
}
//create a new binding and set it for the corresponding parameter in all known defns and decls
binding = new CParameter( paramName );
IASTParameterDeclaration temp = null;
if( definition != null ){
if( definition instanceof IASTStandardFunctionDeclarator ){
IASTParameterDeclaration [] parameters = ((IASTStandardFunctionDeclarator)definition).getParameters();
if( parameters.length > idx ) {
temp = parameters[idx];
ASTQueries.findInnermostDeclarator(temp.getDeclarator()).getName().setBinding( binding );
}
} else if( definition instanceof ICASTKnRFunctionDeclarator ){
fKnRDtor = (ICASTKnRFunctionDeclarator) definition;
IASTName [] parameterNames = fKnRDtor.getParameterNames();
if( parameterNames.length > idx ) {
IASTName n = parameterNames[idx];
n.setBinding( binding );
IASTDeclarator dtor = CVisitor.getKnRParameterDeclarator( fKnRDtor, n );
if( dtor != null ){
dtor.getName().setBinding( binding );
}
}
}
}
if (declarators != null) {
for (IASTDeclarator dtor : declarators) {
if (dtor instanceof IASTStandardFunctionDeclarator) {
IASTStandardFunctionDeclarator fdtor= (IASTStandardFunctionDeclarator) dtor;
if( fdtor.getParameters().length > idx ){
temp = fdtor.getParameters()[idx];
ASTQueries.findInnermostDeclarator(temp.getDeclarator()).getName().setBinding( binding );
}
}
}
}
return binding;
}
protected void updateParameterBindings( IASTFunctionDeclarator fdtor ){
IParameter [] params = getParameters();
if( fdtor instanceof IASTStandardFunctionDeclarator ){
IASTParameterDeclaration [] nps = ((IASTStandardFunctionDeclarator)fdtor).getParameters();
if(params.length < nps.length )
return;
for( int i = 0; i < nps.length; i++ ){
IASTName name = ASTQueries.findInnermostDeclarator(nps[i].getDeclarator()).getName();
name.setBinding( params[i] );
if( params[i] instanceof CParameter )
((CParameter)params[i]).addDeclaration( name );
}
} else {
IASTName [] ns = ((ICASTKnRFunctionDeclarator)fdtor).getParameterNames();
if( params.length > 0 && params.length != ns.length )
return; //problem
for( int i = 0; i < params.length; i++ ){
IASTName name = ns[i];
name.setBinding( params[i] );
IASTDeclarator dtor = CVisitor.getKnRParameterDeclarator( (ICASTKnRFunctionDeclarator) fdtor, name );
if( dtor != null ){
dtor.getName().setBinding( params[i] );
if( params[i] instanceof CParameter )
((CParameter)params[i]).addDeclaration( dtor.getName() );
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IFunction#isStatic()
*/
public boolean isStatic() {
return isStatic(true);
}
public boolean isStatic(boolean resolveAll) {
if( resolveAll && (bits & FULLY_RESOLVED) == 0 ){
resolveAllDeclarations();
}
return hasStorageClass( IASTDeclSpecifier.sc_static );
}
public boolean hasStorageClass( int storage){
IASTDeclarator dtor = definition;
IASTDeclarator[] ds = declarators;
int i = -1;
do{
if( dtor != null ){
IASTNode parent = dtor.getParent();
while( !(parent instanceof IASTDeclaration) )
parent = parent.getParent();
IASTDeclSpecifier declSpec = null;
if( parent instanceof IASTSimpleDeclaration ){
declSpec = ((IASTSimpleDeclaration)parent).getDeclSpecifier();
} else if( parent instanceof IASTFunctionDefinition )
declSpec = ((IASTFunctionDefinition)parent).getDeclSpecifier();
if( declSpec != null && declSpec.getStorageClass() == storage ) {
return true;
}
}
if( ds != null && ++i < ds.length )
dtor = ds[i];
else
break;
} while( dtor != null );
return false;
}
public boolean isExtern() {
return isExtern(true);
}
public boolean isExtern(boolean resolveAll) {
if( resolveAll && (bits & FULLY_RESOLVED) == 0 ){
resolveAllDeclarations();
}
return hasStorageClass( IASTDeclSpecifier.sc_extern);
}
public boolean isAuto() {
if( (bits & FULLY_RESOLVED) == 0 ){
resolveAllDeclarations();
}
return hasStorageClass( IASTDeclSpecifier.sc_auto);
}
public boolean isRegister() {
if( (bits & FULLY_RESOLVED) == 0 ){
resolveAllDeclarations();
}
return hasStorageClass( IASTDeclSpecifier.sc_register);
}
public boolean isInline() {
if( (bits & FULLY_RESOLVED) == 0 ){
resolveAllDeclarations();
}
IASTDeclarator dtor = definition;
IASTDeclarator[] ds = declarators;
int i = -1;
do{
if( dtor != null ){
IASTNode parent = dtor.getParent();
while( !(parent instanceof IASTDeclaration) )
parent = parent.getParent();
IASTDeclSpecifier declSpec = null;
if( parent instanceof IASTSimpleDeclaration ){
declSpec = ((IASTSimpleDeclaration)parent).getDeclSpecifier();
} else if( parent instanceof IASTFunctionDefinition )
declSpec = ((IASTFunctionDefinition)parent).getDeclSpecifier();
if( declSpec != null && declSpec.isInline() )
return true;
}
if( ds != null && ++i < ds.length )
dtor = ds[i];
else
break;
} while( dtor != null );
return false;
}
public boolean takesVarArgs() {
if ((bits & FULLY_RESOLVED) == 0) {
resolveAllDeclarations();
}
if (definition != null) {
if (definition instanceof IASTStandardFunctionDeclarator)
return ((IASTStandardFunctionDeclarator) definition).takesVarArgs();
return false;
}
if (declarators != null) {
for (IASTDeclarator dtor : declarators) {
if (dtor instanceof IASTStandardFunctionDeclarator) {
return ((IASTStandardFunctionDeclarator) dtor).takesVarArgs();
}
}
}
return false;
}
public void setFullyResolved(boolean resolved) {
if( resolved )
bits |= FULLY_RESOLVED;
else
bits &= ~FULLY_RESOLVED;
}
public ILinkage getLinkage() {
return Linkage.C_LINKAGE;
}
public IASTNode[] getDeclarations() {
return declarators;
}
public IASTNode getDefinition() {
return definition;
}
public IBinding getOwner() {
return null;
}
}