/*******************************************************************************
* Copyright (c) 2005, 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) - 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.ast.ASTTypeUtil;
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.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.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
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;
/**
* Implementation of function templates
*/
public class CPPFunctionTemplate extends CPPTemplateDefinition
implements ICPPFunctionTemplate, ICPPInternalFunction {
protected ICPPFunctionType type = null;
public CPPFunctionTemplate(IASTName name) {
super(name);
}
@Override
public void addDefinition(IASTNode node) {
if (!(node instanceof IASTName))
return;
IASTDeclarator fdecl= getDeclaratorByName(node);
if (fdecl instanceof ICPPASTFunctionDeclarator) {
updateFunctionParameterBindings((ICPPASTFunctionDeclarator) fdecl);
super.addDefinition(node);
}
}
@Override
public void addDeclaration(IASTNode node) {
if (!(node instanceof IASTName))
return;
IASTDeclarator fdecl= getDeclaratorByName(node);
if (fdecl == null)
return;
if (fdecl instanceof ICPPASTFunctionDeclarator)
updateFunctionParameterBindings((ICPPASTFunctionDeclarator) fdecl);
super.addDeclaration(node);
}
private ICPPASTFunctionDeclarator getFirstFunctionDtor() {
IASTDeclarator dtor= getDeclaratorByName(getDefinition());
if (dtor instanceof ICPPASTFunctionDeclarator)
return (ICPPASTFunctionDeclarator) dtor;
IASTNode[] decls = getDeclarations();
if (decls != null) {
for (IASTNode decl : decls) {
dtor= getDeclaratorByName(decl);
if (dtor instanceof ICPPASTFunctionDeclarator)
return (ICPPASTFunctionDeclarator) dtor;
}
}
return null;
}
public ICPPParameter[] getParameters() {
ICPPASTFunctionDeclarator fdecl= getFirstFunctionDtor();
if (fdecl != null) {
IASTParameterDeclaration[] params = fdecl.getParameters();
int size = params.length;
if (size == 0) {
return ICPPParameter.EMPTY_CPPPARAMETER_ARRAY;
}
ICPPParameter[] result = new ICPPParameter[size];
for (int i = 0; i < size; i++) {
IASTParameterDeclaration p = params[i];
final IASTName pname = ASTQueries.findInnermostDeclarator(p.getDeclarator()).getName();
final IBinding binding= pname.resolveBinding();
if (binding instanceof ICPPParameter) {
result[i]= (ICPPParameter) binding;
} else {
result[i] = new CPPParameter.CPPParameterProblem(p,
IProblemBinding.SEMANTIC_INVALID_TYPE, pname.toCharArray());
}
}
return result;
}
return CPPBuiltinParameter.createParameterList(getType());
}
public int getRequiredArgumentCount() {
return CPPFunction.getRequiredArgumentCount(getParameters());
}
public boolean hasParameterPack() {
ICPPParameter[] pars= getParameters();
return pars.length > 0 && pars[pars.length-1].isParameterPack();
}
public IScope getFunctionScope() {
return null;
}
public ICPPFunctionType getType() {
if (type == null) {
IASTName name = getTemplateName();
IASTNode parent = name.getParent();
while (parent.getParent() instanceof IASTDeclarator)
parent = parent.getParent();
IType t = getNestedType(CPPVisitor.createType((IASTDeclarator)parent), 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 boolean hasStorageClass(int storage) {
IASTName name = (IASTName) getDefinition();
IASTNode[] ns = getDeclarations();
int i = -1;
do {
if (name != null) {
IASTNode parent = name.getParent();
while (parent != null && !(parent instanceof IASTDeclaration))
parent = parent.getParent();
IASTDeclSpecifier declSpec = getDeclSpecifier((IASTDeclaration) parent);
if (declSpec != null && declSpec.getStorageClass() == storage) {
return true;
}
}
if (ns != null && ++i < ns.length)
name = (IASTName) ns[i];
else
break;
} while (name != null);
return false;
}
protected ICPPASTDeclSpecifier getDeclSpecifier(IASTDeclaration decl) {
if (decl instanceof IASTSimpleDeclaration) {
return (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration)decl).getDeclSpecifier();
}
if (decl instanceof IASTFunctionDefinition) {
return (ICPPASTDeclSpecifier) ((IASTFunctionDefinition)decl).getDeclSpecifier();
}
return null;
}
public IBinding resolveParameter(CPPParameter param) {
int pos= param.getParameterPosition();
final IASTNode[] decls= getDeclarations();
int tdeclLen= decls == null ? 0 : decls.length;
for (int i= -1; i < tdeclLen; i++) {
IASTDeclarator tdecl;
if (i == -1) {
tdecl= getDeclaratorByName(getDefinition());
if (tdecl == null)
continue;
} else if (decls != null){
tdecl= getDeclaratorByName(decls[i]);
if (tdecl == null)
break;
} else {
break;
}
if (tdecl instanceof ICPPASTFunctionDeclarator) {
IASTParameterDeclaration[] params = ((ICPPASTFunctionDeclarator) tdecl).getParameters();
if (pos < params.length) {
final IASTName oName = getParamName(params[pos]);
return oName.resolvePreBinding();
}
}
}
return param;
}
protected void updateFunctionParameterBindings(ICPPASTFunctionDeclarator fdtor) {
IASTParameterDeclaration[] updateParams = fdtor.getParameters();
int k= 0;
final IASTNode[] decls= getDeclarations();
int tdeclLen= decls == null ? 0 : decls.length;
for (int i= -1; i < tdeclLen && k < updateParams.length; i++) {
IASTDeclarator tdecl;
if (i == -1) {
tdecl= getDeclaratorByName(getDefinition());
if (tdecl == null)
continue;
} else if (decls != null) {
tdecl= getDeclaratorByName(decls[i]);
if (tdecl == null)
break;
} else {
break;
}
if (tdecl instanceof ICPPASTFunctionDeclarator) {
IASTParameterDeclaration[] params = ((ICPPASTFunctionDeclarator) 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);
}
}
}
}
private IASTName getParamName(final IASTParameterDeclaration paramDecl) {
return ASTQueries.findInnermostDeclarator(paramDecl.getDeclarator()).getName();
}
public final boolean isStatic() {
return isStatic(true);
}
public boolean isMutable() {
return hasStorageClass(IASTDeclSpecifier.sc_mutable);
}
public boolean isInline() {
IASTName name = (IASTName) getDefinition();
IASTNode[] ns = getDeclarations();
int i = -1;
do {
if (name != null) {
IASTNode parent = name.getParent();
while (parent != null && !(parent instanceof IASTDeclaration))
parent = parent.getParent();
IASTDeclSpecifier declSpec = getDeclSpecifier((IASTDeclaration) parent);
if (declSpec != null && declSpec.isInline())
return true;
}
if (ns != null && ++i < ns.length)
name = (IASTName) ns[i];
else
break;
} while(name != 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(IASTDeclSpecifier.sc_extern);
}
public boolean isDeleted() {
return CPPFunction.isDeletedDefinition(getDefinition());
}
public boolean isAuto() {
return hasStorageClass(IASTDeclSpecifier.sc_auto);
}
public boolean isRegister() {
return hasStorageClass(IASTDeclSpecifier.sc_register);
}
public boolean takesVarArgs() {
ICPPASTFunctionDeclarator fdecl= getFirstFunctionDtor();
if (fdecl != null) {
return fdecl.takesVarArgs();
}
return false;
}
private IASTDeclarator getDeclaratorByName(IASTNode node) {
// skip qualified names and nested declarators.
while (node != null) {
node= node.getParent();
if (node instanceof IASTDeclarator) {
return ASTQueries.findTypeRelevantDeclarator((IASTDeclarator) node);
}
}
return null;
}
public boolean isStatic(boolean resolveAll) {
return hasStorageClass(IASTDeclSpecifier.sc_static);
}
@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 IType[] getExceptionSpecification() {
ICPPASTFunctionDeclarator declarator = getFirstFunctionDtor();
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;
}
}