/******************************************************************************* * Copyright (c) 2004, 2013 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.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; 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; 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; } } @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(); } if (result.length == 1 && SemanticUtil.isVoidType(result[0].getType())) return IParameter.EMPTY_PARAMETER_ARRAY; } 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; } }