| /******************************************************************************* |
| * Copyright (c) 2004, 2012 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) |
| * Sergey Prigogin (Google) |
| *******************************************************************************/ |
| 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.AttributeUtil; |
| 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; |
| 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; |
| |
| 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 = ArrayUtil.append(IASTDeclarator.class, declarators, declarator); |
| } |
| } |
| } |
| |
| @Override |
| public IASTDeclarator getPhysicalNode() { |
| if (definition != null) { |
| return definition; |
| } else if (declarators != null && declarators.length > 0) { |
| return declarators[0]; |
| } |
| return null; |
| } |
| |
| @Override |
| 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 = ArrayUtil.trim(IASTDeclarator.class, declarators); |
| bits |= FULLY_RESOLVED; |
| bits &= ~RESOLUTION_IN_PROGRESS; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.core.dom.ast.IFunction#getParameters() |
| */ |
| @Override |
| 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()); |
| } |
| |
| @Override |
| public String getName() { |
| return getASTName().toString(); |
| } |
| |
| @Override |
| public char[] getNameCharArray() { |
| return getASTName().toCharArray(); |
| } |
| |
| private IASTName getASTName() { |
| return ASTQueries.findInnermostDeclarator(getPhysicalNode()).getName(); |
| } |
| |
| @Override |
| public IScope getScope() { |
| IASTDeclarator dtor = getPhysicalNode(); |
| if (dtor != null) |
| return CVisitor.getContainingScope(ASTQueries.findOutermostDeclarator(dtor).getParent()); |
| return null; |
| } |
| |
| @Override |
| public IScope getFunctionScope() { |
| if (definition != null) { |
| IASTFunctionDefinition def = (IASTFunctionDefinition) definition.getParent(); |
| return def.getScope(); |
| } |
| return null; |
| } |
| |
| @Override |
| 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()); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public boolean isStatic() { |
| return isStatic(true); |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| public boolean isExtern() { |
| return isExtern(true); |
| } |
| |
| public boolean isExtern(boolean resolveAll) { |
| if (resolveAll && (bits & FULLY_RESOLVED) == 0) { |
| resolveAllDeclarations(); |
| } |
| return hasStorageClass(IASTDeclSpecifier.sc_extern); |
| } |
| |
| @Override |
| public boolean isAuto() { |
| if ((bits & FULLY_RESOLVED) == 0) { |
| resolveAllDeclarations(); |
| } |
| return hasStorageClass(IASTDeclSpecifier.sc_auto); |
| } |
| |
| @Override |
| public boolean isRegister() { |
| if ((bits & FULLY_RESOLVED) == 0) { |
| resolveAllDeclarations(); |
| } |
| return hasStorageClass(IASTDeclSpecifier.sc_register); |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| 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; |
| } |
| |
| @Override |
| public void setFullyResolved(boolean resolved) { |
| if (resolved) { |
| bits |= FULLY_RESOLVED; |
| } else { |
| bits &= ~FULLY_RESOLVED; |
| } |
| } |
| |
| @Override |
| public ILinkage getLinkage() { |
| return Linkage.C_LINKAGE; |
| } |
| |
| @Override |
| public IASTDeclarator[] getDeclarations() { |
| return declarators; |
| } |
| |
| @Override |
| public IASTFunctionDeclarator getDefinition() { |
| return definition; |
| } |
| |
| @Override |
| public IBinding getOwner() { |
| return null; |
| } |
| |
| @Override |
| public boolean isNoReturn() { |
| IASTFunctionDeclarator dtor = getPreferredDtor(); |
| return dtor != null && AttributeUtil.hasNoreturnAttribute(dtor); |
| } |
| |
| protected IASTFunctionDeclarator getPreferredDtor() { |
| IASTFunctionDeclarator dtor = getDefinition(); |
| if (dtor != null) |
| return dtor; |
| |
| IASTDeclarator[] dtors = getDeclarations(); |
| if (dtors != null) { |
| for (IASTDeclarator declarator : dtors) { |
| if (declarator instanceof IASTFunctionDeclarator) |
| return (IASTFunctionDeclarator) declarator; |
| } |
| } |
| return null; |
| } |
| } |