blob: cbc148906847a2d8857ef344be2cff1c28fdf706 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2016 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)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
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.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.ICPPFunctionTemplate;
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.AttributeUtil;
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.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
* Implementation of function templates.
*/
public class CPPFunctionTemplate extends CPPTemplateDefinition
implements ICPPFunctionTemplate, ICPPInternalFunction {
protected ICPPFunctionType declaredType;
protected ICPPFunctionType type;
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;
}
@Override
public ICPPParameter[] getParameters() {
ICPPASTFunctionDeclarator declarator= null;
IASTDeclarator dtor= getDeclaratorByName(getDefinition());
if (dtor instanceof ICPPASTFunctionDeclarator)
declarator = (ICPPASTFunctionDeclarator) dtor;
IASTNode[] decls = getDeclarations();
if (decls != null) {
// In case of multiple function declarations we select the one with the most
// default parameter values.
int defaultValuePosition = -1;
for (IASTNode decl : decls) {
dtor= getDeclaratorByName(decl);
if (dtor instanceof ICPPASTFunctionDeclarator) {
if (declarator == null) {
declarator = (ICPPASTFunctionDeclarator) dtor;
} else {
ICPPASTFunctionDeclarator contender = (ICPPASTFunctionDeclarator) dtor;
if (defaultValuePosition < 0)
defaultValuePosition = CPPFunction.findFirstDefaultValue(declarator.getParameters());
int pos = CPPFunction.findFirstDefaultValue(contender.getParameters());
if (pos < defaultValuePosition) {
declarator = contender;
defaultValuePosition = pos;
}
}
}
}
}
if (declarator != null) {
IASTParameterDeclaration[] params = declarator.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 param = params[i];
final IASTName pname = ASTQueries.findInnermostDeclarator(param.getDeclarator()).getName();
final IBinding binding= pname.resolveBinding();
if (binding instanceof ICPPParameter) {
result[i]= (ICPPParameter) binding;
} else {
result[i] = new CPPParameter.CPPParameterProblem(
param, IProblemBinding.SEMANTIC_INVALID_TYPE, pname.toCharArray());
}
}
if (result.length == 1 && SemanticUtil.isVoidType(result[0].getType()))
return ICPPParameter.EMPTY_CPPPARAMETER_ARRAY; // f(void) is the same as f()
return result;
}
return CPPBuiltinParameter.createParameterList(getType());
}
@Override
public int getRequiredArgumentCount() {
return CPPFunction.getRequiredArgumentCount(getParameters());
}
@Override
public boolean hasParameterPack() {
ICPPParameter[] pars= getParameters();
return pars.length > 0 && pars[pars.length - 1].isParameterPack();
}
@Override
public IScope getFunctionScope() {
return null;
}
@Override
public ICPPFunctionType getDeclaredType() {
if (declaredType == null) {
IASTName name = getTemplateName();
IASTNode parent = name.getParent();
while (parent.getParent() instanceof IASTDeclarator)
parent = parent.getParent();
IType t = CPPVisitor.createType((IASTDeclarator) parent, CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS);
declaredType = CPPFunction.toFunctionType(t);
}
return declaredType;
}
@Override
public ICPPFunctionType getType() {
if (type == null) {
IASTName name = getTemplateName();
IASTNode parent = name.getParent();
while (parent.getParent() instanceof IASTDeclarator)
parent = parent.getParent();
IType t = CPPVisitor.createType((IASTDeclarator) parent);
// TODO(nathanridge): Do we need to search for the definition here, if t is
// ProblemType.NO_NAME, as in CPPFunction?
type = CPPFunction.toFunctionType(t);
}
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;
}
@Override
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 < 0) {
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 < 0) {
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();
}
@Override
public final boolean isStatic() {
return isStatic(true);
}
@Override
public boolean isMutable() {
return hasStorageClass(IASTDeclSpecifier.sc_mutable);
}
@Override
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;
}
@Override
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;
}
@Override
public boolean isExtern() {
return hasStorageClass(IASTDeclSpecifier.sc_extern);
}
@Override
public boolean isAuto() {
return hasStorageClass(IASTDeclSpecifier.sc_auto);
}
@Override
public boolean isConstexpr() {
ICPPASTFunctionDefinition functionDefinition = CPPFunction.getFunctionDefinition(getDefinition());
if (functionDefinition == null)
return false;
return ((ICPPASTDeclSpecifier) functionDefinition.getDeclSpecifier()).isConstexpr();
}
@Override
public boolean isDeleted() {
return CPPFunction.isDeletedDefinition(getDefinition());
}
@Override
public boolean isRegister() {
return hasStorageClass(IASTDeclSpecifier.sc_register);
}
@Override
public boolean takesVarArgs() {
ICPPASTFunctionDeclarator fdecl= getFirstFunctionDtor();
if (fdecl != null) {
return fdecl.takesVarArgs();
}
return false;
}
@Override
public boolean isNoReturn() {
ICPPASTFunctionDeclarator fdecl= getFirstFunctionDtor();
if (fdecl != null) {
return AttributeUtil.hasNoreturnAttribute(fdecl);
}
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;
}
@Override
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();
}
@Override
public IType[] getExceptionSpecification() {
ICPPASTFunctionDeclarator declarator = getFirstFunctionDtor();
if (declarator != null) {
IASTTypeId[] typeIds = declarator.getExceptionSpecification();
if (typeIds.equals(ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION)) {
return null;
}
if (typeIds.equals(IASTTypeId.EMPTY_TYPEID_ARRAY)) {
return IType.EMPTY_TYPE_ARRAY;
}
IType[] types = new IType[typeIds.length];
for (int i = 0; i < typeIds.length; ++i) {
types[i] = CPPVisitor.createType(typeIds[i]);
}
return types;
}
return null;
}
@Override
public ICPPExecution getFunctionBodyExecution() {
if (!isConstexpr()) {
return null;
}
return CPPFunction.computeFunctionBodyExecution(getDefinition());
}
}