/******************************************************************************* * 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) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; 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.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.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; 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.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.Linkage; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.ProblemFunctionType; 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; /** * Binding for c++ function */ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInternalFunction { protected IASTDeclarator[] declarations; protected ICPPASTFunctionDeclarator definition; protected ICPPFunctionType type = null; private static final int FULLY_RESOLVED = 1; private static final int RESOLUTION_IN_PROGRESS = 1 << 1; private int bits = 0; public CPPFunction(IASTDeclarator declarator) { if (declarator != null) { IASTNode parent = ASTQueries.findOutermostDeclarator(declarator).getParent(); if (parent instanceof IASTFunctionDefinition) { if (declarator instanceof ICPPASTFunctionDeclarator) { definition = (ICPPASTFunctionDeclarator) declarator; } } else { declarations = new IASTDeclarator[] { declarator }; } IASTName name= getASTName(); name.setBinding(this); } } private void resolveAllDeclarations() { if ((bits & (FULLY_RESOLVED | RESOLUTION_IN_PROGRESS)) == 0) { bits |= RESOLUTION_IN_PROGRESS; IASTTranslationUnit tu = null; if (definition != null) { tu = definition.getTranslationUnit(); } else if (declarations != null) { tu = declarations[0].getTranslationUnit(); } else { //implicit binding IScope scope = getScope(); IASTNode node = ASTInternal.getPhysicalNodeOfScope(scope); if (node != null) { tu = node.getTranslationUnit(); } } if (tu != null) { CPPVisitor.getDeclarations(tu, this); } declarations = (IASTDeclarator[]) ArrayUtil.trim(IASTDeclarator.class, declarations); bits |= FULLY_RESOLVED; bits &= ~RESOLUTION_IN_PROGRESS; } } public IASTDeclarator[] getDeclarations() { return declarations; } public ICPPASTFunctionDeclarator getDefinition() { return definition; } public final void addDefinition(IASTNode node) { IASTDeclarator dtor = extractRelevantDtor(node); if (dtor instanceof ICPPASTFunctionDeclarator) { ICPPASTFunctionDeclarator fdtor= (ICPPASTFunctionDeclarator) dtor; updateFunctionParameterBindings(fdtor); definition = fdtor; } } public final void addDeclaration(IASTNode node) { IASTDeclarator dtor = extractRelevantDtor(node); if (dtor == null) { return; } // function could be declared via a typedef if (dtor instanceof ICPPASTFunctionDeclarator) { updateFunctionParameterBindings((ICPPASTFunctionDeclarator) dtor); } if (declarations == null || declarations.length == 0) { declarations = new IASTDeclarator[] { dtor }; } else { // Keep the lowest offset declaration in [0] if (((ASTNode)node).getOffset() < ((ASTNode)declarations[0]).getOffset()) { declarations = ArrayUtil.prepend(declarations, dtor); } else { declarations = ArrayUtil.append(declarations, dtor); } } } private IASTDeclarator extractRelevantDtor(IASTNode node) { while (node instanceof IASTName) node = node.getParent(); if (!(node instanceof IASTDeclarator)) return null; return ASTQueries.findTypeRelevantDeclarator((IASTDeclarator) node); } public ICPPParameter[] getParameters() { IASTStandardFunctionDeclarator dtor = getPreferredDtor(); if (dtor == null) { return CPPBuiltinParameter.createParameterList(getType()); } IASTParameterDeclaration[] params = dtor.getParameters(); int size = params.length; ICPPParameter[] result = new ICPPParameter[size]; if (size > 0) { for (int i = 0; i < size; i++) { IASTParameterDeclaration p = params[i]; final IASTName name = getParamName(p); final IBinding binding= name.resolveBinding(); if (binding instanceof ICPPParameter) { result[i]= (ICPPParameter) binding; } else { result[i] = new CPPParameter.CPPParameterProblem(p, IProblemBinding.SEMANTIC_INVALID_TYPE, name.toCharArray()); } } } return result; } public IScope getFunctionScope() { resolveAllDeclarations(); if (definition != null) { return definition.getFunctionScope(); } for (IASTDeclarator dtor : declarations) { if (dtor instanceof ICPPASTFunctionDeclarator) { return ((ICPPASTFunctionDeclarator) dtor).getFunctionScope(); } } // function declaration via typedef return null; } public String getName() { return getASTName().toString(); } public char[] getNameCharArray() { return getASTName().getSimpleID(); } protected IASTName getASTName() { IASTDeclarator dtor = (definition != null) ? definition : declarations[0]; dtor= ASTQueries.findInnermostDeclarator(dtor); IASTName name= dtor.getName(); if (name instanceof ICPPASTQualifiedName) { IASTName[] ns = ((ICPPASTQualifiedName)name).getNames(); name = ns[ns.length - 1]; } return name; } public IScope getScope() { IASTName n = getASTName(); IScope scope = CPPVisitor.getContainingScope(n); if (scope instanceof ICPPClassScope) { ICPPASTDeclSpecifier declSpec = null; if (definition != null) { IASTNode node = ASTQueries.findOutermostDeclarator(definition).getParent(); IASTFunctionDefinition def = (IASTFunctionDefinition) node; declSpec = (ICPPASTDeclSpecifier) def.getDeclSpecifier(); } else { IASTNode node = ASTQueries.findOutermostDeclarator(declarations[0]).getParent(); IASTSimpleDeclaration decl = (IASTSimpleDeclaration)node; declSpec = (ICPPASTDeclSpecifier) decl.getDeclSpecifier(); } if (declSpec.isFriend()) { try { while (scope instanceof ICPPClassScope) { scope = scope.getParent(); } } catch (DOMException e) { } } } return scope; } public ICPPFunctionType getType() { if (type == null) { final IType t = getNestedType(CPPVisitor.createType((definition != null) ? definition : declarations[0]), TDEF); if (t instanceof ICPPFunctionType) { type = (ICPPFunctionType) t; } else if (t instanceof ISemanticProblem){ type= new ProblemFunctionType(((ISemanticProblem) t).getID()); } else { // This case is unexpected type = new ProblemFunctionType(ISemanticProblem.TYPE_UNRESOLVED_NAME); } } return type; } public IBinding resolveParameter(CPPParameter param) { int pos= param.getParameterPosition(); int tdeclLen= declarations == null ? 0 : declarations.length; for (int i= -1; i < tdeclLen; i++) { ICPPASTFunctionDeclarator tdecl; if (i == -1) { tdecl= definition; if (tdecl == null) continue; } else { final IASTDeclarator dtor= declarations[i]; if (!(dtor instanceof ICPPASTFunctionDeclarator)) { if (dtor == null) { break; } continue; } tdecl= (ICPPASTFunctionDeclarator) dtor; } IASTParameterDeclaration[] params = tdecl.getParameters(); if (pos < params.length) { final IASTName oName = getParamName(params[pos]); return oName.resolvePreBinding(); } } return param; } private IASTName getParamName(final IASTParameterDeclaration paramDecl) { return ASTQueries.findInnermostDeclarator(paramDecl.getDeclarator()).getName(); } protected final void updateFunctionParameterBindings(ICPPASTFunctionDeclarator fdtor) { IASTParameterDeclaration[] updateParams = fdtor.getParameters(); int k= 0; int tdeclLen= declarations == null ? 0 : declarations.length; for (int i= -1; i < tdeclLen && k < updateParams.length; i++) { ICPPASTFunctionDeclarator tdecl; if (i == -1) { tdecl= definition; if (tdecl == null) continue; } else { final IASTDeclarator dtor= declarations[i]; if (!(dtor instanceof ICPPASTFunctionDeclarator)) { if (dtor == null) { break; } continue; } tdecl= (ICPPASTFunctionDeclarator) dtor; } IASTParameterDeclaration[] params = tdecl.getParameters(); int end= Math.min(params.length, updateParams.length); for (; k < end; k++) { final IASTName oName = getParamName(params[k]); IBinding b= oName.resolvePreBinding(); IASTName n = getParamName(updateParams[k]); n.setBinding(b); ASTInternal.addDeclaration(b, n); } } } public final boolean isStatic() { return isStatic(true); } public boolean isStatic(boolean resolveAll) { if (resolveAll && (bits & FULLY_RESOLVED) == 0) { resolveAllDeclarations(); } return hasStorageClass(this, IASTDeclSpecifier.sc_static); } // static public boolean isStatic // //2 state bits, most significant = whether or not we've figure this out yet // //least significant = whether or not we are static // int state = (bits & IS_STATIC) >> 2; // if (state > 1) return (state % 2 != 0); // // IASTDeclSpecifier declSpec = null; // IASTFunctionDeclarator dtor = (IASTFunctionDeclarator) getDefinition(); // if (dtor != null) { // declSpec = ((IASTFunctionDefinition)dtor.getParent()).getDeclSpecifier(); // if (declSpec.getStorageClass() == IASTDeclSpecifier.sc_static) { // bits |= 3 << 2; // return true; // } // } // // IASTFunctionDeclarator[] dtors = (IASTFunctionDeclarator[]) getDeclarations(); // if (dtors != null) { // for (int i = 0; i < dtors.length; i++) { // IASTNode parent = dtors[i].getParent(); // declSpec = ((IASTSimpleDeclaration)parent).getDeclSpecifier(); // if (declSpec.getStorageClass() == IASTDeclSpecifier.sc_static) { // bits |= 3 << 2; // return true; // } // } // } // bits |= 2 << 2; // return false; // } public String[] getQualifiedName() { return CPPVisitor.getQualifiedName(this); } public char[][] getQualifiedNameCharArray() { return CPPVisitor.getQualifiedNameCharArray(this); } public boolean isGloballyQualified() throws DOMException { IScope scope = getScope(); while (scope != null) { if (scope instanceof ICPPBlockScope) return false; scope = scope.getParent(); } return true; } static public boolean hasStorageClass(ICPPInternalFunction function, int storage) { IASTDeclarator dtor = (IASTDeclarator) function.getDefinition(); IASTNode[] ds = function.getDeclarations(); 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 = (IASTDeclarator) ds[i]; } else { break; } } while (dtor != null); return false; } public boolean isDeleted() { return isDeletedDefinition(getDefinition()); } public static boolean isDeletedDefinition(IASTNode def) { while (def != null && !(def instanceof IASTDeclaration)) { def= def.getParent(); } if (def instanceof ICPPASTFunctionDefinition) { return ((ICPPASTFunctionDefinition) def).isDeleted(); } return false; } public boolean isMutable() { return false; } public boolean isInline() { IASTDeclarator dtor = getDefinition(); IASTDeclarator[] ds = getDeclarations(); 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 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; } public boolean isExtern() { return hasStorageClass(this, IASTDeclSpecifier.sc_extern); } public boolean isAuto() { return hasStorageClass(this, IASTDeclSpecifier.sc_auto); } public boolean isRegister() { return hasStorageClass(this, IASTDeclSpecifier.sc_register); } public boolean takesVarArgs() { ICPPASTFunctionDeclarator dtor= getPreferredDtor(); return dtor != null ? dtor.takesVarArgs() : false; } public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(getName()); IFunctionType t = getType(); result.append(t != null ? ASTTypeUtil.getParameterTypeString(t) : "()"); //$NON-NLS-1$ return result.toString(); } public IBinding getOwner() { return CPPVisitor.findNameOwner(getASTName(), false); } public IType[] getExceptionSpecification() { ICPPASTFunctionDeclarator declarator = getPreferredDtor(); if (declarator != null) { IASTTypeId[] astTypeIds= declarator.getExceptionSpecification(); if (astTypeIds.equals(ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION)) return null; if (astTypeIds.equals(IASTTypeId.EMPTY_TYPEID_ARRAY)) return IType.EMPTY_TYPE_ARRAY; IType[] typeIds = new IType[astTypeIds.length]; for (int i= 0; i < astTypeIds.length; ++i) { typeIds[i] = CPPVisitor.createType(astTypeIds[i]); } return typeIds; } return null; } protected ICPPASTFunctionDeclarator getPreferredDtor() { ICPPASTFunctionDeclarator dtor = getDefinition(); if (dtor != null) return dtor; IASTDeclarator[] dtors = getDeclarations(); if (dtors != null) { for (IASTDeclarator declarator : dtors) { if (declarator instanceof ICPPASTFunctionDeclarator) return (ICPPASTFunctionDeclarator) declarator; } } return null; } public int getRequiredArgumentCount() { return getRequiredArgumentCount(getParameters()); } public static int getRequiredArgumentCount(ICPPParameter[] pars) { int result= pars.length; while(result > 0) { final ICPPParameter p = pars[result-1]; if (p.hasDefaultValue() || p.isParameterPack()) { result--; } else { if (pars.length == 1 && SemanticUtil.isVoidType(p.getType())) { return 0; } return result; } } return 0; } public boolean hasParameterPack() { ICPPParameter[] pars= getParameters(); return pars.length > 0 && pars[pars.length-1].isParameterPack(); } }