1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-20 15:35:24 +02:00

Bug 516627 - Add support for generic lambdas

Change-Id: I2e8d16cfe2dc58b77e36fa7a6957506c90b7e75a
This commit is contained in:
Nathan Ridge 2017-05-16 03:41:52 -04:00
parent f579acd381
commit 3147cc4732
10 changed files with 586 additions and 16 deletions

View file

@ -13,6 +13,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2; package org.eclipse.cdt.core.parser.tests.ast2;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.GenericLambdaTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionTests; import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.VariableTemplateTests; import org.eclipse.cdt.core.parser.tests.ast2.cxx14.VariableTemplateTests;
import org.eclipse.cdt.core.parser.tests.prefix.CompletionTestSuite; import org.eclipse.cdt.core.parser.tests.prefix.CompletionTestSuite;
@ -59,8 +60,10 @@ public class DOMParserTestSuite extends TestCase {
suite.addTest(AccessControlTests.suite()); suite.addTest(AccessControlTests.suite());
suite.addTest(VariableReadWriteFlagsTest.suite()); suite.addTest(VariableReadWriteFlagsTest.suite());
suite.addTest(AST2CPPAttributeTests.suite()); suite.addTest(AST2CPPAttributeTests.suite());
// C++14 tests
suite.addTest(VariableTemplateTests.suite()); suite.addTest(VariableTemplateTests.suite());
suite.addTestSuite(ReturnTypeDeductionTests.class); suite.addTestSuite(ReturnTypeDeductionTests.class);
suite.addTestSuite(GenericLambdaTests.class);
return suite; return suite;
} }
} }

View file

@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* 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
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2.cxx14;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.internal.index.tests.IndexBindingResolutionTestBase;
/**
* Index tests for C++14 generic lambdas.
*/
public class GenericLambdaIndexTests extends IndexBindingResolutionTestBase {
public GenericLambdaIndexTests() {
setStrategy(new SinglePDOMTestStrategy(true));
}
// auto Identity = [](auto a){ return a; };
// auto three = Identity(3);
// auto hello = Identity("hello");
public void testBasicCall() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableType("three", CommonCPPTypes.int_);
helper.assertVariableType("hello", CommonCPPTypes.pointerToConstChar);
}
// // Adapted from the example in [expr.prim.lambda] p7 in the standard.
// auto Identity = [](auto a){ return a; };
// void f1(int(*)(int));
// void f2(char(*)(int));
// void g(int(*)(int));
// void g(char(*)(char));
// void h(int(*)(int)); // #1
// void h(char(*)(int)); // #2
// int main() {
// f1(Identity); // ok
// f2(Identity); // error: not convertible
// g(Identity); // error: ambiguous
// h(Identity); // ok: calls #1
// }
public void testConversionToFunctionPointer() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertNonProblem("f1(Id", "f1");
helper.assertProblem("f2(Id", "f2");
helper.assertProblem("g(Id", "g");
IFunction h1 = helper.assertNonProblem("h(int", "h");
IFunction hCall = helper.assertNonProblem("h(Id", "h");
assertSame(h1, hCall);
}
// template <typename... T>
// struct tuple {};
//
// template <typename... T>
// tuple<T...> make_tuple(T...);
//
// auto L = [](auto... args) { return make_tuple(args...); };
//
// struct Cat { void meow(); };
//
// Cat foo(tuple<int, char>);
// Cat bar(tuple<int, char, float>);
//
// void waldo(Cat);
// int main() {
// waldo(foo(L(42, 'x')));
// waldo(bar(L(42, 'x', 42.0f)));
// }
public void _testVariadicAutoParameter() throws Exception {
// TODO: To pass this test, we need to store lambda parameters in the index.
checkBindings();
}
// // Adapted from the example in [expr.prim.lambda] p6 in the standard.
// namespace std {
// struct ostream {
// template <typename T>
// ostream& operator<<(const T&);
// };
// ostream cout;
// }
// auto vglambda = [](auto printer) {
// return [=](auto&&... ts) {
// return [=]() {
// return printer(ts...);
// };
// };
// };
// auto p = vglambda(
// [](auto v1, auto v2, auto v3) {
// return std::cout << v1 << v2 << v3;
// });
// auto q = p(1, 'a', 3.14);
// void waldo(const std::ostream&);
// int main() {
// waldo(q());
// }
public void testNestedGenericLambdas() throws Exception {
checkBindings();
}
}

View file

@ -0,0 +1,103 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* 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
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2.cxx14;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
/**
* AST tests for C++14 generic lambdas.
*/
public class GenericLambdaTests extends AST2CPPTestBase {
// auto Identity = [](auto a){ return a; };
// auto three = Identity(3);
// auto hello = Identity("hello");
public void testBasicCall() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableType("three", CommonCPPTypes.int_);
helper.assertVariableType("hello", CommonCPPTypes.pointerToConstChar);
}
// // Adapted from the example in [expr.prim.lambda] p7 in the standard.
// auto Identity = [](auto a){ return a; };
// void f1(int(*)(int));
// void f2(char(*)(int));
// void g(int(*)(int));
// void g(char(*)(char));
// void h(int(*)(int)); // #1
// void h(char(*)(int)); // #2
// void j(int&(*)(int*));
// int main() {
// f1(Identity); // ok
// f2(Identity); // error: not convertible
// g(Identity); // error: ambiguous
// h(Identity); // ok: calls #1
// j([](auto* a) -> auto& { return *a; }); // ok
// }
public void testConversionToFunctionPointer() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertNonProblem("f1(Id", "f1");
helper.assertProblem("f2(Id", "f2");
helper.assertProblem("g(Id", "g");
IFunction h1 = helper.assertNonProblem("h(int", "h");
IFunction hCall = helper.assertNonProblem("h(Id", "h");
assertSame(h1, hCall);
helper.assertNonProblem("j([]", "j");
}
// template <typename... T>
// struct tuple {};
//
// template <typename... T>
// tuple<T...> make_tuple(T...);
//
// auto L = [](auto... args) { return make_tuple(args...); };
//
// struct Cat { void meow(); };
//
// Cat foo(tuple<int, char>);
// Cat bar(tuple<int, char, float>);
//
// void waldo(Cat);
//
// int main() {
// waldo(foo(L(42, 'x')));
// waldo(bar(L(42, 'x', 42.0f)));
// }
public void testVariadicAutoParameter() throws Exception {
parseAndCheckBindings();
}
// // Adapted from the example in [expr.prim.lambda] p6 in the standard.
// namespace std {
// struct ostream {
// template <typename T>
// ostream& operator<<(const T&);
// };
// ostream cout;
// }
// auto vglambda = [](auto printer) {
// return [=](auto&&... ts) {
// return [=]() {
// return printer(ts...);
// };
// };
// };
// auto p = vglambda(
// [](auto v1, auto v2, auto v3) {
// return std::cout << v1 << v2 << v3;
// });
// auto q = p(1, 'a', 3.14);
// void waldo(const std::ostream&);
// int main() {
// waldo(q());
// }
public void testNestedGenericLambdas() throws Exception {
parseAndCheckBindings();
}
}

View file

@ -11,6 +11,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.index.tests; package org.eclipse.cdt.internal.index.tests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.GenericLambdaIndexTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionIndexTests; import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionIndexTests;
import junit.framework.Test; import junit.framework.Test;
@ -37,7 +38,9 @@ public class IndexTests extends TestSuite {
suite.addTest(IndexMultiVariantHeaderTest.suite()); suite.addTest(IndexMultiVariantHeaderTest.suite());
suite.addTest(IndexMultiFileTest.suite()); suite.addTest(IndexMultiFileTest.suite());
// C++14 index test suites
suite.addTestSuite(ReturnTypeDeductionIndexTests.class); suite.addTestSuite(ReturnTypeDeductionIndexTests.class);
suite.addTestSuite(GenericLambdaIndexTests.class);
IndexCPPBindingResolutionBugs.addTests(suite); IndexCPPBindingResolutionBugs.addTests(suite);
IndexCPPBindingResolutionTest.addTests(suite); IndexCPPBindingResolutionTest.addTests(suite);

View file

@ -40,6 +40,7 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr
private IASTImplicitName fClosureTypeName; private IASTImplicitName fClosureTypeName;
private IASTImplicitName fImplicitFunctionCallName; private IASTImplicitName fImplicitFunctionCallName;
private IASTImplicitName fImplicitConversionOperatorName;
private ICPPEvaluation fEvaluation; private ICPPEvaluation fEvaluation;
@ -106,10 +107,32 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr
return fImplicitFunctionCallName; return fImplicitFunctionCallName;
} }
private IASTImplicitName getConversionOperatorName() {
if (fImplicitConversionOperatorName == null) {
final CPPClosureType closureType = getExpressionType();
ICPPFunction conversionOperator = closureType.getConversionOperator();
if (conversionOperator != null) {
CPPASTImplicitName name = new CPPASTImplicitName(closureType.getNameCharArray(), this);
name.setBinding(conversionOperator);
name.setIsDefinition(true);
if (fBody instanceof ASTNode) {
name.setOffsetAndLength(((ASTNode) fBody).getOffset(), 1);
}
fImplicitConversionOperatorName = name;
}
}
return fImplicitConversionOperatorName;
}
@Override @Override
public IASTImplicitName[] getImplicitNames() { public IASTImplicitName[] getImplicitNames() {
IASTImplicitName conversionOperatorName = getConversionOperatorName();
if (conversionOperatorName == null) {
return new IASTImplicitName[] { getFunctionCallOperatorName() }; return new IASTImplicitName[] { getFunctionCallOperatorName() };
} }
return new IASTImplicitName[] { getFunctionCallOperatorName(), getConversionOperatorName() };
}
@Override @Override
public IASTImplicitDestructorName[] getImplicitDestructorNames() { public IASTImplicitDestructorName[] getImplicitDestructorNames() {
@ -138,8 +161,13 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr
if (fDeclarator != null && !fDeclarator.accept(visitor)) if (fDeclarator != null && !fDeclarator.accept(visitor))
return false; return false;
if (visitor.shouldVisitImplicitNames && !getFunctionCallOperatorName().accept(visitor)) if (visitor.shouldVisitImplicitNames) {
for (IASTImplicitName name : getImplicitNames()) {
if (!name.accept(visitor)) {
return false; return false;
}
}
}
if (fBody != null && !fBody.accept(visitor)) if (fBody != null && !fBody.accept(visitor))
return false; return false;

View file

@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
@ -35,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef; 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.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression.CaptureDefault; 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.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
@ -45,9 +47,11 @@ 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.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.internal.core.dom.Linkage; import org.eclipse.cdt.internal.core.dom.Linkage;
@ -65,6 +69,8 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
private final ICPPASTLambdaExpression fLambdaExpression; private final ICPPASTLambdaExpression fLambdaExpression;
private ICPPMethod[] fMethods; private ICPPMethod[] fMethods;
private ClassScope fScope; private ClassScope fScope;
// Used for generic lambdas; null otherwise.
private ICPPTemplateParameter[] fInventedTemplateParameters;
public CPPClosureType(ICPPASTLambdaExpression lambdaExpr) { public CPPClosureType(ICPPASTLambdaExpression lambdaExpr) {
fLambdaExpression= lambdaExpr; fLambdaExpression= lambdaExpr;
@ -111,17 +117,45 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
for (int i = 0; i < params.length; i++) { for (int i = 0; i < params.length; i++) {
params[i]= new CPPParameter(parameterTypes[i], i); params[i]= new CPPParameter(parameterTypes[i], i);
} }
m= new CPPImplicitMethod(scope, OverloadableOperator.PAREN.toCharArray(), ft, params, false) { char[] operatorParensName = OverloadableOperator.PAREN.toCharArray();
if (isGeneric()) {
m = new CPPImplicitMethodTemplate(getInventedTemplateParameterList(), scope, operatorParensName,
ft, params, false) {
@Override @Override
public boolean isImplicit() { return false; } public boolean isImplicit() { return false; }
}; };
} else {
m= new CPPImplicitMethod(scope, operatorParensName, ft, params, false) {
@Override
public boolean isImplicit() { return false; }
};
}
result[4]= m; result[4]= m;
// Conversion operator // Conversion operator
if (needConversionOperator) { if (needConversionOperator) {
final CPPFunctionType conversionTarget = new CPPFunctionType(returnType, parameterTypes); final CPPFunctionType conversionTarget = new CPPFunctionType(returnType, parameterTypes);
ft= new CPPFunctionType(conversionTarget, IType.EMPTY_TYPE_ARRAY, true, false, false, false, false); ft= new CPPFunctionType(conversionTarget, IType.EMPTY_TYPE_ARRAY, true, false, false, false, false);
m= new CPPImplicitMethod(scope, CPPASTConversionName.createName(conversionTarget, null), ft, params, false); char[] conversionOperatorName = CPPASTConversionName.createName(conversionTarget, null);
if (isGeneric()) {
ICPPTemplateParameter[] templateParams = getInventedTemplateParameterList();
// Clone the template parameters, since they are used by the function call operator,
// and the same parameters cannot participate in two different templates.
ICPPTemplateParameter[] templateParamClones = new ICPPTemplateParameter[templateParams.length];
for (int i = 0; i < templateParams.length; ++i) {
templateParamClones[i] = (ICPPTemplateParameter) ((IType) templateParams[i]).clone();
}
m = new CPPImplicitMethodTemplate(templateParamClones, scope,
conversionOperatorName, ft, params, false) {
@Override
public boolean isImplicit() { return false; }
};
} else {
m= new CPPImplicitMethod(scope, conversionOperatorName, ft, params, false) {
@Override
public boolean isImplicit() { return false; }
};
}
result[5]= m; result[5]= m;
} }
return result; return result;
@ -167,6 +201,40 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
} }
public boolean isGeneric() {
return getInventedTemplateParameterList().length > 0;
}
public ICPPTemplateParameter[] getInventedTemplateParameterList() {
if (fInventedTemplateParameters == null) {
fInventedTemplateParameters = computeInventedTemplateParameterList();
}
return fInventedTemplateParameters;
}
public ICPPTemplateParameter[] computeInventedTemplateParameterList() {
ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator();
ICPPTemplateParameter[] result = ICPPTemplateParameter.EMPTY_TEMPLATE_PARAMETER_ARRAY;
if (lambdaDtor != null) {
// Create an invented template parameter for every "auto" in the lambda's
// function parameter list.
int position = 0;
ICPPASTParameterDeclaration[] params = lambdaDtor.getParameters();
for (ICPPASTParameterDeclaration param : params) {
IASTDeclSpecifier declSpec = param.getDeclSpecifier();
if (declSpec instanceof IASTSimpleDeclSpecifier) {
if (((IASTSimpleDeclSpecifier) declSpec).getType() == IASTSimpleDeclSpecifier.t_auto) {
boolean isPack = param.getDeclarator().declaresParameterPack();
result = ArrayUtil.append(result, new CPPImplicitTemplateTypeParameter(
fLambdaExpression, position, isPack));
position++;
}
}
}
}
return ArrayUtil.trim(result);
}
private IType[] getParameterTypes() { private IType[] getParameterTypes() {
ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator(); ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator();
if (lambdaDtor != null) { if (lambdaDtor != null) {

View file

@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
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.dom.ast.cpp.ICPPTemplateParameter;
/**
* Binding for implicit method templates.
*
* Used for the function call operator and pointer-to-function conversion operator
* of a generic lambda.
*/
public class CPPImplicitMethodTemplate extends CPPImplicitMethod implements ICPPFunctionTemplate {
private ICPPTemplateParameter[] fTemplateParameters;
public CPPImplicitMethodTemplate(ICPPTemplateParameter[] templateParameters, ICPPClassScope scope,
char[] name, ICPPFunctionType type, ICPPParameter[] params, boolean isConstexpr) {
super(scope, name, type, params, isConstexpr);
fTemplateParameters = templateParameters;
for (ICPPTemplateParameter parameter : templateParameters) {
if (parameter instanceof CPPImplicitTemplateTypeParameter) {
((CPPImplicitTemplateTypeParameter) parameter).setContainingTemplate(this);
}
}
}
@Override
public ICPPTemplateParameter[] getTemplateParameters() {
return fTemplateParameters;
}
}

View file

@ -0,0 +1,164 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
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.ICPPScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.core.runtime.PlatformObject;
/**
* Binding for implicit template type parameters.
*
* Used for the template type parameters of implicit method templates.
*/
public class CPPImplicitTemplateTypeParameter extends PlatformObject implements ICPPTemplateTypeParameter,
ICPPUnknownType, ICPPUnknownBinding {
private int fParameterID;
private boolean fIsParameterPack;
private ICPPScope fUnknownScope;
// The containing (implicit) template definition.
private ICPPTemplateDefinition fContainingTemplate;
// The AST node that triggered the creation of the implicit template.
// For methods of generic lambdas, this is the lambda expression.
private IASTNode fNode;
public CPPImplicitTemplateTypeParameter(IASTNode node, int position, boolean isParameterPack) {
fParameterID = computeParameterID(position);
fIsParameterPack = isParameterPack;
fNode = node;
}
private int computeParameterID(int position) {
int nesting = 0;
for (IASTNode node = fNode; node != null; node = node.getParent()) {
if (node instanceof ICPPASTInternalTemplateDeclaration) {
nesting = ((ICPPASTInternalTemplateDeclaration) node).getNestingLevel();
break;
}
}
return (nesting << 16) + (position & 0xffff);
}
public void setContainingTemplate(ICPPTemplateDefinition containingTemplate) {
fContainingTemplate = containingTemplate;
}
@Override
public String[] getQualifiedName() throws DOMException {
return new String[] { getName() };
}
@Override
public char[][] getQualifiedNameCharArray() throws DOMException {
return new char[][] { getNameCharArray() };
}
@Override
public boolean isGloballyQualified() throws DOMException {
return false;
}
@Override
public String getName() {
return new String();
}
@Override
public char[] getNameCharArray() {
// Implicit template parameters are unnamed.
return CharArrayUtils.EMPTY;
}
@Override
public ILinkage getLinkage() {
return Linkage.CPP_LINKAGE;
}
@Override
public IBinding getOwner() {
return fContainingTemplate;
}
@Override
public IScope getScope() throws DOMException {
// TODO: Do we need an implicit template scope for the implicit template
// parameter to live in?
return CPPVisitor.getContainingScope(fNode);
}
@Override
public short getParameterPosition() {
return (short) fParameterID;
}
@Override
public short getTemplateNestingLevel() {
return (short) (fParameterID >> 16);
}
@Override
public int getParameterID() {
return fParameterID;
}
@Override
public ICPPTemplateArgument getDefaultValue() {
// Implicit template parameters do not have default arguments.
return null;
}
@Override
public boolean isParameterPack() {
return fIsParameterPack;
}
@Override
public IType getDefault() throws DOMException {
return null;
}
@Override
public boolean isSameType(IType type) {
if (type == this)
return true;
if (type instanceof ITypedef)
return type.isSameType(this);
if (!(type instanceof ICPPTemplateTypeParameter))
return false;
return getParameterID() == ((ICPPTemplateParameter) type).getParameterID();
}
@Override
public Object clone() {
return new CPPImplicitTemplateTypeParameter(fNode, getParameterPosition(), fIsParameterPack);
}
@Override
public ICPPScope asScope() throws DOMException {
if (fUnknownScope == null) {
fUnknownScope = new CPPUnknownTypeScope(this, null);
}
return fUnknownScope;
}
}

View file

@ -170,6 +170,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.util.ReturnStatementVisitor; import org.eclipse.cdt.core.dom.ast.util.ReturnStatementVisitor;
import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndex;
@ -195,6 +196,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructor; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplate;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration;
@ -1887,10 +1889,17 @@ public class CPPVisitor extends ASTQueries {
public static IType createType(final ICPPASTParameterDeclaration pdecl, boolean forFuncType) { public static IType createType(final ICPPASTParameterDeclaration pdecl, boolean forFuncType) {
IASTDeclSpecifier pDeclSpec = pdecl.getDeclSpecifier(); IASTDeclSpecifier pDeclSpec = pdecl.getDeclSpecifier();
ICPPASTDeclarator pDtor = pdecl.getDeclarator(); ICPPASTDeclarator pDtor = pdecl.getDeclarator();
IType pt = createType(pDeclSpec); IType pt;
PlaceholderKind placeholder = usesAuto(pDeclSpec);
if (placeholder != null) {
pt = createAutoType(pDeclSpec, pDtor, 0, placeholder);
} else {
pt = createType(pDeclSpec);
if (pDtor != null) { if (pDtor != null) {
pt = createType(pt, pDtor); pt = createType(pt, pDtor);
} }
}
pt= adjustParameterType(pt, forFuncType); pt= adjustParameterType(pt, forFuncType);
if (pDtor != null && findInnermostDeclarator(pDtor).declaresParameterPack()) { if (pDtor != null && findInnermostDeclarator(pDtor).declaresParameterPack()) {
@ -2118,6 +2127,40 @@ public class CPPVisitor extends ASTQueries {
return type; return type;
} }
private static IType createAutoParameterType(IASTDeclSpecifier declSpec, IASTDeclarator declarator,
ICPPASTParameterDeclaration declaration, PlaceholderKind placeholder) {
// decltype(auto) is not allowed in parameters.
if (placeholder == PlaceholderKind.DecltypeAuto) {
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
}
// In C++14, auto is only allowed in lambda parameters.
// In the Concepts TS (not implemented yet), this restriction is removed.
ICPPASTFunctionDeclarator functionDeclarator = (ICPPASTFunctionDeclarator) declaration.getParent();
if (functionDeclarator.getParent() instanceof ICPPASTLambdaExpression) {
ICPPASTLambdaExpression lambda = (ICPPASTLambdaExpression) functionDeclarator.getParent();
CPPClosureType closure = (CPPClosureType) lambda.getExpressionType();
ICPPTemplateParameter[] templateParameters = closure.getInventedTemplateParameterList();
// Find the invented template parameter corresponding to this 'auto'.
int templateParameterIndex = -1;
for (ICPPASTParameterDeclaration parameter : functionDeclarator.getParameters()) {
if (usesAuto(parameter.getDeclSpecifier()) != null) {
++templateParameterIndex;
}
if (parameter == declaration)
break;
}
if (templateParameterIndex >= 0 && templateParameterIndex < templateParameters.length) {
ICPPTemplateParameter templateParameter = templateParameters[templateParameterIndex];
if (templateParameter instanceof ICPPTemplateTypeParameter) {
return createType((ICPPTemplateTypeParameter) templateParameter, declarator);
}
}
}
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
}
private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator, private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator,
int flags, PlaceholderKind placeholderKind) { int flags, PlaceholderKind placeholderKind) {
IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ? IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ?
@ -2134,6 +2177,10 @@ public class CPPVisitor extends ASTQueries {
return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator, flags, return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator, flags,
placeholderKind); placeholderKind);
} }
if (declarator.getParent() instanceof ICPPASTParameterDeclaration) {
return createAutoParameterType(declSpec, declarator,
(ICPPASTParameterDeclaration) declarator.getParent(), placeholderKind);
}
ICPPASTInitializerClause autoInitClause= null; ICPPASTInitializerClause autoInitClause= null;
IASTNode parent = declarator.getParent().getParent(); IASTNode parent = declarator.getParent().getParent();
if (parent instanceof ICPPASTNewExpression) { if (parent instanceof ICPPASTNewExpression) {

View file

@ -262,14 +262,19 @@ abstract public class IndexerASTVisitor extends ASTVisitor {
final IASTName closureName = lambdaExpr.getClosureTypeName(); final IASTName closureName = lambdaExpr.getClosureTypeName();
visit(closureName, fDefinitionName); visit(closureName, fDefinitionName);
// Definition of call operator
IASTName callOp= lambdaExpr.getFunctionCallOperatorName(); // Definition of call operator and conversion operator (if applicable)
visit(callOp, closureName); IASTName[] ops = lambdaExpr.getImplicitNames();
for (IASTName op : ops) {
visit(op, closureName);
}
IBinding owner = CPPVisitor.findDeclarationOwner(lambdaExpr, true); IBinding owner = CPPVisitor.findDeclarationOwner(lambdaExpr, true);
boolean localToFunction = owner instanceof IFunction; boolean localToFunction = owner instanceof IFunction;
if (!localToFunction) if (!localToFunction)
push(callOp, lambdaExpr); // Local closures don't appear in the index, so don't refer to them. // Local closures don't appear in the index, so don't refer to them.
push(lambdaExpr.getFunctionCallOperatorName(), lambdaExpr);
ICPPASTFunctionDeclarator dtor = lambdaExpr.getDeclarator(); ICPPASTFunctionDeclarator dtor = lambdaExpr.getDeclarator();
if (dtor != null && !dtor.accept(this)) if (dtor != null && !dtor.accept(this))