mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-20 23:45:23 +02:00
Bug 516627 - Add support for generic lambdas
Change-Id: I2e8d16cfe2dc58b77e36fa7a6957506c90b7e75a
This commit is contained in:
parent
f579acd381
commit
3147cc4732
10 changed files with 586 additions and 16 deletions
|
@ -13,6 +13,7 @@
|
|||
*******************************************************************************/
|
||||
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.VariableTemplateTests;
|
||||
import org.eclipse.cdt.core.parser.tests.prefix.CompletionTestSuite;
|
||||
|
@ -59,8 +60,10 @@ public class DOMParserTestSuite extends TestCase {
|
|||
suite.addTest(AccessControlTests.suite());
|
||||
suite.addTest(VariableReadWriteFlagsTest.suite());
|
||||
suite.addTest(AST2CPPAttributeTests.suite());
|
||||
// C++14 tests
|
||||
suite.addTest(VariableTemplateTests.suite());
|
||||
suite.addTestSuite(ReturnTypeDeductionTests.class);
|
||||
suite.addTestSuite(GenericLambdaTests.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
*******************************************************************************/
|
||||
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 junit.framework.Test;
|
||||
|
@ -37,7 +38,9 @@ public class IndexTests extends TestSuite {
|
|||
suite.addTest(IndexMultiVariantHeaderTest.suite());
|
||||
suite.addTest(IndexMultiFileTest.suite());
|
||||
|
||||
// C++14 index test suites
|
||||
suite.addTestSuite(ReturnTypeDeductionIndexTests.class);
|
||||
suite.addTestSuite(GenericLambdaIndexTests.class);
|
||||
|
||||
IndexCPPBindingResolutionBugs.addTests(suite);
|
||||
IndexCPPBindingResolutionTest.addTests(suite);
|
||||
|
|
|
@ -40,6 +40,7 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr
|
|||
|
||||
private IASTImplicitName fClosureTypeName;
|
||||
private IASTImplicitName fImplicitFunctionCallName;
|
||||
private IASTImplicitName fImplicitConversionOperatorName;
|
||||
|
||||
private ICPPEvaluation fEvaluation;
|
||||
|
||||
|
@ -106,10 +107,32 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr
|
|||
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
|
||||
public IASTImplicitName[] getImplicitNames() {
|
||||
IASTImplicitName conversionOperatorName = getConversionOperatorName();
|
||||
if (conversionOperatorName == null) {
|
||||
return new IASTImplicitName[] { getFunctionCallOperatorName() };
|
||||
}
|
||||
return new IASTImplicitName[] { getFunctionCallOperatorName(), getConversionOperatorName() };
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTImplicitDestructorName[] getImplicitDestructorNames() {
|
||||
|
@ -138,8 +161,13 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr
|
|||
if (fDeclarator != null && !fDeclarator.accept(visitor))
|
||||
return false;
|
||||
|
||||
if (visitor.shouldVisitImplicitNames && !getFunctionCallOperatorName().accept(visitor))
|
||||
if (visitor.shouldVisitImplicitNames) {
|
||||
for (IASTImplicitName name : getImplicitNames()) {
|
||||
if (!name.accept(visitor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fBody != null && !fBody.accept(visitor))
|
||||
return false;
|
||||
|
|
|
@ -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.IASTName;
|
||||
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.IASTTypeId;
|
||||
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.cpp.ICPPASTFunctionDeclarator;
|
||||
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.ICPPASTTemplateId;
|
||||
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.ICPPMethod;
|
||||
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.index.IIndexBinding;
|
||||
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.IContentAssistMatcher;
|
||||
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 ICPPMethod[] fMethods;
|
||||
private ClassScope fScope;
|
||||
// Used for generic lambdas; null otherwise.
|
||||
private ICPPTemplateParameter[] fInventedTemplateParameters;
|
||||
|
||||
public CPPClosureType(ICPPASTLambdaExpression lambdaExpr) {
|
||||
fLambdaExpression= lambdaExpr;
|
||||
|
@ -111,17 +117,45 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
|
|||
for (int i = 0; i < params.length; 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
|
||||
public boolean isImplicit() { return false; }
|
||||
};
|
||||
} else {
|
||||
m= new CPPImplicitMethod(scope, operatorParensName, ft, params, false) {
|
||||
@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, 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;
|
||||
}
|
||||
return result;
|
||||
|
@ -167,6 +201,40 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
|
|||
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() {
|
||||
ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator();
|
||||
if (lambdaDtor != null) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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.ICPPTemplateParameter;
|
||||
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.util.ReturnStatementVisitor;
|
||||
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.CPPClassTemplate;
|
||||
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.CPPConstructorTemplate;
|
||||
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) {
|
||||
IASTDeclSpecifier pDeclSpec = pdecl.getDeclSpecifier();
|
||||
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) {
|
||||
pt = createType(pt, pDtor);
|
||||
}
|
||||
}
|
||||
|
||||
pt= adjustParameterType(pt, forFuncType);
|
||||
|
||||
if (pDtor != null && findInnermostDeclarator(pDtor).declaresParameterPack()) {
|
||||
|
@ -2118,6 +2127,40 @@ public class CPPVisitor extends ASTQueries {
|
|||
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,
|
||||
int flags, PlaceholderKind placeholderKind) {
|
||||
IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ?
|
||||
|
@ -2134,6 +2177,10 @@ public class CPPVisitor extends ASTQueries {
|
|||
return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator, flags,
|
||||
placeholderKind);
|
||||
}
|
||||
if (declarator.getParent() instanceof ICPPASTParameterDeclaration) {
|
||||
return createAutoParameterType(declSpec, declarator,
|
||||
(ICPPASTParameterDeclaration) declarator.getParent(), placeholderKind);
|
||||
}
|
||||
ICPPASTInitializerClause autoInitClause= null;
|
||||
IASTNode parent = declarator.getParent().getParent();
|
||||
if (parent instanceof ICPPASTNewExpression) {
|
||||
|
|
|
@ -262,14 +262,19 @@ abstract public class IndexerASTVisitor extends ASTVisitor {
|
|||
final IASTName closureName = lambdaExpr.getClosureTypeName();
|
||||
visit(closureName, fDefinitionName);
|
||||
|
||||
// Definition of call operator
|
||||
IASTName callOp= lambdaExpr.getFunctionCallOperatorName();
|
||||
visit(callOp, closureName);
|
||||
|
||||
// Definition of call operator and conversion operator (if applicable)
|
||||
IASTName[] ops = lambdaExpr.getImplicitNames();
|
||||
for (IASTName op : ops) {
|
||||
visit(op, closureName);
|
||||
|
||||
}
|
||||
|
||||
IBinding owner = CPPVisitor.findDeclarationOwner(lambdaExpr, true);
|
||||
boolean localToFunction = owner instanceof IFunction;
|
||||
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();
|
||||
if (dtor != null && !dtor.accept(this))
|
||||
|
|
Loading…
Add table
Reference in a new issue