/*******************************************************************************
* Copyright (c) 2010, 2011 Wind River Systems, Inc. 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:
* Markus Schorn (Wind River Systems) - initial API and implementation
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression.CaptureDefault;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
import org.eclipse.core.runtime.PlatformObject;
/**
* Binding for a class type.
*/
public class CPPClosureType extends PlatformObject implements ICPPClassType, ICPPInternalBinding {
private static final CPPBasicType NO_RETURN_TYPE = new CPPBasicType(Kind.eUnspecified, 0);
private final ICPPASTLambdaExpression fLambdaExpression;
private ICPPMethod[] fMethods;
private ClassScope fScope;
public CPPClosureType(ICPPASTLambdaExpression lambdaExpr) {
fLambdaExpression= lambdaExpr;
}
private ICPPMethod[] createMethods() {
boolean needConversionOperator=
fLambdaExpression.getCaptureDefault() == CaptureDefault.UNSPECIFIED &&
fLambdaExpression.getCaptures().length == 0;
final ICPPClassScope scope= getCompositeScope();
ICPPMethod[] result= new ICPPMethod[needConversionOperator ? 6 : 5];
// Deleted default constructor: A()
CPPImplicitConstructor ctor= new CPPImplicitConstructor(scope, CharArrayUtils.EMPTY, ICPPParameter.EMPTY_CPPPARAMETER_ARRAY);
ctor.setDeleted(true);
result[0]= ctor;
// Copy constructor: A(const A &)
IType pType = new CPPReferenceType(SemanticUtil.constQualify(this), false);
ICPPParameter[] ps = new ICPPParameter[] { new CPPParameter(pType, 0) };
ctor = new CPPImplicitConstructor(scope, CharArrayUtils.EMPTY, ps);
result[1]= ctor;
// Deleted copy assignment operator: A& operator = (const A &)
IType refType = new CPPReferenceType(this, false);
ICPPFunctionType ft= CPPVisitor.createImplicitFunctionType(refType, ps, false, false);
ICPPMethod m = new CPPImplicitMethod(scope, OverloadableOperator.ASSIGN.toCharArray(), ft, ps);
result[2]= m;
// Destructor: ~A()
ft= CPPVisitor.createImplicitFunctionType(NO_RETURN_TYPE, ICPPParameter.EMPTY_CPPPARAMETER_ARRAY, false, false);
m = new CPPImplicitMethod(scope, new char[] {'~'}, ft, ICPPParameter.EMPTY_CPPPARAMETER_ARRAY);
result[3]= m;
// Function call operator
final IType returnType= getReturnType();
final IType[] parameterTypes= getParameterTypes();
ft= new CPPFunctionType(returnType, parameterTypes, isMutable(), false, false);
ICPPParameter[] params = new ICPPParameter[parameterTypes.length];
for (int i = 0; i < params.length; i++) {
params[i]= new CPPParameter(parameterTypes[i], 0);
}
m= new CPPImplicitMethod(scope, OverloadableOperator.PAREN.toCharArray(), ft, params) {
@Override
public boolean isImplicit() {return false;}
};
result[4]= m;
// Conversion operator
if (needConversionOperator) {
final CPPFunctionType conversionTarget = new CPPFunctionType(returnType, parameterTypes);
ft= new CPPFunctionType(conversionTarget, IType.EMPTY_TYPE_ARRAY, true, false, false);
m= new CPPImplicitMethod(scope, CPPASTConversionName.createName(conversionTarget, null), ft, params);
result[5]= m;
}
return result;
}
public ICPPMethod getFunctionCallOperator() {
return getMethods()[4];
}
private boolean isMutable() {
ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator();
return lambdaDtor != null && lambdaDtor.isMutable();
}
private IType getReturnType() {
ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator();
if (lambdaDtor != null) {
IASTTypeId trailingReturnType = lambdaDtor.getTrailingReturnType();
if (trailingReturnType != null) {
return CPPVisitor.createType(trailingReturnType);
}
}
IASTCompoundStatement body = fLambdaExpression.getBody();
if (body != null) {
IASTStatement[] stmts = body.getStatements();
if (stmts.length > 0) {
// Gnu extension allows to deduce return type in complex compound statements
IASTStatement stmt= stmts[stmts.length-1];
if (stmt instanceof IASTReturnStatement) {
IASTReturnStatement rtstmt= (IASTReturnStatement) stmt;
IASTExpression expr= rtstmt.getReturnValue();
if (expr != null) {
IType type= expr.getExpressionType();
type= Conversions.lvalue_to_rvalue(type);
if (type != null) {
return type;
}
}
}
}
}
return CPPSemantics.VOID_TYPE;
}
private IType[] getParameterTypes() {
ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator();
if (lambdaDtor != null) {
return CPPVisitor.createParameterTypes(lambdaDtor);
}
return IType.EMPTY_TYPE_ARRAY;
}
public final String getName() {
return ""; //$NON-NLS-1$
}
public char[] getNameCharArray() {
return CharArrayUtils.EMPTY;
}
public IScope getScope() {
return CPPVisitor.getContainingScope(fLambdaExpression);
}
public ICPPClassScope getCompositeScope() {
if (fScope == null) {
fScope= new ClassScope();
}
return fScope;
}
public int getKey() {
return k_class;
}
public String[] getQualifiedName() {
return CPPVisitor.getQualifiedName(this);
}
public char[][] getQualifiedNameCharArray() {
return CPPVisitor.getQualifiedNameCharArray(this);
}
public boolean isGloballyQualified() {
return getOwner() == null;
}
public ILinkage getLinkage() {
return Linkage.CPP_LINKAGE;
}
public boolean isSameType(IType type) {
if (type == this)
return true;
if (type instanceof ITypedef || type instanceof IIndexBinding)
return type.isSameType(this);
return false;
}
public ICPPBase[] getBases() {
return ICPPBase.EMPTY_BASE_ARRAY;
}
public ICPPField[] getFields() {
return ICPPField.EMPTY_CPPFIELD_ARRAY;
}
public ICPPField[] getDeclaredFields() {
return ICPPField.EMPTY_CPPFIELD_ARRAY;
}
public ICPPMethod[] getMethods() {
if (fMethods == null) {
fMethods= createMethods();
}
return fMethods;
}
public ICPPMethod[] getAllDeclaredMethods() {
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
}
public ICPPMethod[] getDeclaredMethods() {
return ICPPMethod.EMPTY_CPPMETHOD_ARRAY;
}
public ICPPConstructor[] getConstructors() {
ICPPMethod[] methods= getMethods();
int i= 0;
for (; i < methods.length; i++) {
if (!(methods[i] instanceof ICPPConstructor)) {
break;
}
}
ICPPConstructor[] result= new ICPPConstructor[i];
System.arraycopy(methods, 0, result, 0, i);
return result;
}
public IBinding[] getFriends() {
return IBinding.EMPTY_BINDING_ARRAY;
}
public ICPPClassType[] getNestedClasses() {
return ICPPClassType.EMPTY_CLASS_ARRAY;
}
public IField findField(String name) {
return null;
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
}
return null;
}
/**
* For debugging purposes, only.
*/
@Override
public String toString() {
char[] name= ASTTypeUtil.createNameForAnonymous(this);
if (name != null)
return new String(name);
return null;
}
public IBinding getOwner() {
return CPPVisitor.findDeclarationOwner(fLambdaExpression, true);
}
public boolean isAnonymous() {
return false;
}
public IASTNode getDefinition() {
return fLambdaExpression;
}
public IASTNode[] getDeclarations() {
return IASTNode.EMPTY_NODE_ARRAY;
}
public void addDefinition(IASTNode node) {
}
public void addDeclaration(IASTNode node) {
}
private final class ClassScope implements ICPPClassScope {
public EScopeKind getKind() {
return EScopeKind.eClassType;
}
public IName getScopeName() {
return null;
}
public IScope getParent() {
return getScope();
}
private IBinding getBinding(char[] name) {
for (ICPPMethod m : getMethods()) {
if (!(m instanceof ICPPConstructor) && CharArrayUtils.equals(name, m.getNameCharArray())) {
return m;
}
}
return null;
}
private IBinding[] getBindings(char[] name) {
IBinding m= getBinding(name);
if (m != null) {
return new IBinding[] {m};
}
return IBinding.EMPTY_BINDING_ARRAY;
}
private IBinding[] getPrefixBindings(char[] name) {
List<IBinding> result= new ArrayList<IBinding>();
IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(name);
for (ICPPMethod m : getMethods()) {
if (!(m instanceof ICPPConstructor)) {
if (matcher.match(m.getNameCharArray())) {
result.add(m);
}
}
}
return result.toArray(new IBinding[result.size()]);
}
public IBinding[] find(String name) {
return getBindings(name.toCharArray());
}
public IBinding getBinding(IASTName name, boolean resolve) {
if (name instanceof ICPPASTTemplateId)
return null;
return getBinding(name.getSimpleID());
}
public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet acceptLocalBindings) {
return getBinding(name, resolve);
}
public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup) {
if (name instanceof ICPPASTTemplateId)
return IBinding.EMPTY_BINDING_ARRAY;
if (prefixLookup)
return getPrefixBindings(name.getSimpleID());
return getBindings(name.getSimpleID());
}
public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup,
IIndexFileSet acceptLocalBindings) {
return getBindings(name, resolve, prefixLookup);
}
public ICPPClassType getClassType() {
return CPPClosureType.this;
}
public ICPPMethod[] getImplicitMethods() {
return getMethods();
}
public ICPPConstructor[] getConstructors() {
return CPPClosureType.this.getConstructors();
}
}
}