/*******************************************************************************
* 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
* Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
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.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.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
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.dom.ast.cpp.ICPPParameterPackType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.core.index.IIndexBinding;
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;
/**
* The specialization of a friend function in the context of a class specialization,
* also used as base class for function instances.
*/
public class CPPFunctionSpecialization extends CPPSpecialization implements ICPPFunction, ICPPInternalFunction {
private ICPPFunctionType type = null;
private ICPPParameter[] fParams = null;
private IType[] specializedExceptionSpec = null;
public CPPFunctionSpecialization(ICPPFunction orig, IBinding owner, ICPPTemplateParameterMap argMap) {
super(orig, owner, argMap);
}
private ICPPFunction getFunction() {
return (ICPPFunction) getSpecializedBinding();
}
public ICPPParameter[] getParameters() {
if (fParams == null) {
ICPPFunction function = getFunction();
ICPPParameter[] params = function.getParameters();
if (params.length == 0) {
fParams= params;
} else {
// Because of parameter packs there can be more or less parameters in the specialization
final ICPPTemplateParameterMap tparMap = getTemplateParameterMap();
IType[] ptypes= getType().getParameterTypes();
final int length = ptypes.length;
ICPPParameter par= null;
fParams = new ICPPParameter[length];
for (int i = 0; i < length; i++) {
if (i < params.length) {
par= params[i];
} // else reuse last parameter (which should be a pack)
fParams[i] = new CPPParameterSpecialization(par, this, ptypes[i], tparMap);
}
}
}
return fParams;
}
public int getRequiredArgumentCount() {
return ((ICPPFunction) getSpecializedBinding()).getRequiredArgumentCount();
}
public boolean hasParameterPack() {
return ((ICPPFunction) getSpecializedBinding()).hasParameterPack();
}
public IScope getFunctionScope() {
return null;
}
public ICPPFunctionType getType() {
if (type == null) {
ICPPFunction function = (ICPPFunction) getSpecializedBinding();
type = (ICPPFunctionType) specializeType(function.getType());
}
return type;
}
public boolean isMutable() {
return false;
}
public boolean isDeleted() {
IASTNode def = getDefinition();
if (def != null)
return CPPFunction.isDeletedDefinition(def);
IBinding f = getSpecializedBinding();
if (f instanceof ICPPFunction) {
return ((ICPPFunction) f).isDeleted();
}
return false;
}
public boolean isInline() {
if (getDefinition() != null) {
IASTNode def = getDefinition();
while (!(def instanceof IASTFunctionDefinition))
def = def.getParent();
return ((IASTFunctionDefinition)def).getDeclSpecifier().isInline();
}
return getFunction().isInline();
}
public boolean isExternC() {
if (CPPVisitor.isExternC(getDefinition())) {
return true;
}
return getFunction().isExternC();
}
public boolean isStatic() {
return isStatic(true);
}
public boolean isStatic(boolean resolveAll) {
//TODO resolveAll
IBinding f = getSpecializedBinding();
if (f instanceof ICPPInternalFunction)
return ((ICPPInternalFunction)f).isStatic(resolveAll);
if (f instanceof IIndexBinding && f instanceof ICPPFunction) {
return ((ICPPFunction) f).isStatic();
}
return CPPFunction.hasStorageClass(this, IASTDeclSpecifier.sc_static);
}
public boolean isExtern() {
ICPPFunction f = (ICPPFunction) getSpecializedBinding();
if (f != null)
return f.isExtern();
return CPPFunction.hasStorageClass(this, IASTDeclSpecifier.sc_extern);
}
public boolean isAuto() {
ICPPFunction f = (ICPPFunction) getSpecializedBinding();
if (f != null)
return f.isAuto();
return CPPFunction.hasStorageClass(this, IASTDeclSpecifier.sc_auto);
}
public boolean isRegister() {
ICPPFunction f = (ICPPFunction) getSpecializedBinding();
if (f != null)
return f.isRegister();
return CPPFunction.hasStorageClass(this, IASTDeclSpecifier.sc_register);
}
public boolean takesVarArgs() {
ICPPFunction f = (ICPPFunction) getSpecializedBinding();
if (f != null)
return f.takesVarArgs();
ICPPASTFunctionDeclarator dtor = (ICPPASTFunctionDeclarator) getDefinition();
if (dtor != null) {
return dtor.takesVarArgs();
}
ICPPASTFunctionDeclarator[] ds = (ICPPASTFunctionDeclarator[]) getDeclarations();
if (ds != null && ds.length > 0) {
return ds[0].takesVarArgs();
}
return false;
}
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++) {
ICPPASTFunctionDeclarator tdecl;
if (i == -1) {
tdecl= (ICPPASTFunctionDeclarator) getDefinition();
if (tdecl == null)
continue;
} else if (decls != null){
tdecl= (ICPPASTFunctionDeclarator) decls[i];
if (tdecl == null)
break;
} else {
break;
}
IASTParameterDeclaration[] params = 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++) {
ICPPASTFunctionDeclarator tdecl;
if (i == -1) {
tdecl= (ICPPASTFunctionDeclarator) getDefinition();
if (tdecl == null)
continue;
} else if (decls != null) {
tdecl= (ICPPASTFunctionDeclarator) decls[i];
if (tdecl == null)
break;
} else {
break;
}
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);
}
}
}
private IASTName getParamName(final IASTParameterDeclaration paramDecl) {
return ASTQueries.findInnermostDeclarator(paramDecl.getDeclarator()).getName();
}
private ICPPASTFunctionDeclarator extractFunctionDtor(IASTNode node) {
if (node instanceof IASTName)
node = node.getParent();
if (node instanceof IASTDeclarator == false)
return null;
node= ASTQueries.findTypeRelevantDeclarator((IASTDeclarator) node);
if (node instanceof ICPPASTFunctionDeclarator == false)
return null;
return (ICPPASTFunctionDeclarator) node;
}
@Override
public void addDefinition(IASTNode node) {
ICPPASTFunctionDeclarator dtor = extractFunctionDtor(node);
if (dtor != null) {
updateFunctionParameterBindings(dtor);
super.addDefinition(dtor);
}
}
@Override
public void addDeclaration(IASTNode node) {
ICPPASTFunctionDeclarator dtor = extractFunctionDtor(node);
if (dtor != null) {
updateFunctionParameterBindings(dtor);
super.addDeclaration(dtor);
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(getName());
IFunctionType t = getType();
result.append(t != null ? ASTTypeUtil.getParameterTypeString(t) : "()"); //$NON-NLS-1$
ICPPTemplateParameterMap tpmap= getTemplateParameterMap();
if (tpmap != null) {
result.append(" "); //$NON-NLS-1$
result.append(tpmap.toString());
}
return result.toString();
}
public IType[] getExceptionSpecification() {
if (specializedExceptionSpec == null) {
ICPPFunction function = (ICPPFunction) getSpecializedBinding();
IType[] types = function.getExceptionSpecification();
if (types != null) {
IType[] specializedTypeList = new IType[types.length];
int j=0;
for (int i=0; i<types.length; ++i) {
final IType origType = types[i];
if (origType instanceof ICPPParameterPackType) {
IType[] specialized= specializeTypePack((ICPPParameterPackType) origType);
if (specialized.length != 1) {
IType[] x= new IType[specializedTypeList.length + specialized.length-1];
System.arraycopy(specializedTypeList, 0, x, 0, j);
specializedTypeList= x;
}
for (IType iType : specialized) {
specializedTypeList[j++] = iType;
}
} else {
specializedTypeList[j++] = specializeType(origType);
}
}
specializedExceptionSpec= specializedTypeList;
}
}
return specializedExceptionSpec;
}
}