From 46461fc18350a8224ac55e6043a5676f1b5380fc Mon Sep 17 00:00:00 2001 From: Przemyslaw Gorszkowski Date: Tue, 25 Jun 2013 15:41:17 +0200 Subject: [PATCH] C++: code completion for lambda calls support for lambdas, e.g.: struct S { int bar; }; []() { return new S; } ()->bar; [] { return new S; } ()->bar; []() ->S* { return new S(); } ()->bar; []() throw() { return new S(); } ()->bar; []() throw()->S* { return new S(); } ()->bar; Task-number: QTCREATORBUG-9523 Change-Id: I43fbf6f0ee0bb11411c53c984df75ef33a276466 Reviewed-by: Erik Verbruggen --- src/libs/cplusplus/ExpressionUnderCursor.cpp | 24 ++++ src/libs/cplusplus/ResolveExpression.cpp | 17 +++ src/libs/cplusplus/ResolveExpression.h | 2 + src/plugins/cpptools/cppcompletion_test.cpp | 135 +++++++++++++++++++ src/plugins/cpptools/cpptoolsplugin.h | 7 + 5 files changed, 185 insertions(+) diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index 370a4d110e3..df002672ee0 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -176,6 +176,30 @@ int ExpressionUnderCursor::startOfExpression_helper(BackwardsScanner &tk, int in else if (tk[lessIndex - 1].is(T_SLOT)) return startOfExpression(tk, lessIndex); } + } else if (tk[matchingBraceIndex - 1].is(T_RBRACE)) { + // lambda: [](){} () + int leftBraceIndex = tk.startOfMatchingBrace(matchingBraceIndex); + if (matchingBraceIndex != leftBraceIndex) { + int currentIndex = leftBraceIndex; + while (currentIndex >= 0) { + if (tk[currentIndex-1].is(T_RPAREN)) { + int leftParenIndex = tk.startOfMatchingBrace(currentIndex); + if (tk[leftParenIndex-1].is(T_THROW)) { + currentIndex = leftParenIndex-1; + } else if (tk[leftParenIndex-1].is(T_RBRACKET)) { + int leftBracketIndex = tk.startOfMatchingBrace(leftParenIndex); + if (leftBracketIndex != leftParenIndex-1) + return leftBracketIndex; + } + } else if (tk[currentIndex-1].is(T_RBRACKET)) { + int leftBracketIndex = tk.startOfMatchingBrace(currentIndex); + if (leftBracketIndex != currentIndex-1) + return leftBracketIndex; + } else { + --currentIndex; + } + } + } } return startOfExpression(tk, matchingBraceIndex); } diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 9b09c2c5b59..63dc2b92b25 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -366,6 +366,18 @@ bool ResolveExpression::visit(CompoundExpressionAST *ast) return false; } +bool ResolveExpression::visit(LambdaExpressionAST *ast) +{ + accept(ast->statement); + return false; +} + +bool ResolveExpression::visit(ReturnStatementAST *ast) +{ + accept(ast->expression); + return false; +} + bool ResolveExpression::visit(NestedExpressionAST *ast) { accept(ast->expression); @@ -626,6 +638,11 @@ bool ResolveExpression::visit(CallAST *ast) { const QList baseResults = resolve(ast->base_expression, _scope); + if (ast->base_expression->asLambdaExpression()) { + _results = baseResults; + return false; + } + // Compute the types of the actual arguments. unsigned actualArgumentCount = 0; diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h index 68720fae0f1..b261dc39a28 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -104,6 +104,8 @@ protected: virtual bool visit(UnaryExpressionAST *ast); virtual bool visit(CompoundLiteralAST *ast); virtual bool visit(CompoundExpressionAST *ast); + virtual bool visit(LambdaExpressionAST *ast); + virtual bool visit(ReturnStatementAST *ast); //names virtual bool visit(QualifiedNameAST *ast); diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index d4f1b008381..01c8072cf32 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -2690,3 +2690,138 @@ void CppToolsPlugin::test_completion_enum_inside_function_QTCREATORBUG5456() QVERIFY(completions.contains(QLatin1String("e2"))); QVERIFY(completions.contains(QLatin1String("e3"))); } + +void CppToolsPlugin::test_completion_lambdaCalls_1() +{ + TestData data; + data.srcText = + "struct S { int bar; };\n" + "void foo()\n" + "{\n" + " @\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("[](){ return new S; } ()->"); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 2); + QVERIFY(completions.contains(QLatin1String("S"))); + QVERIFY(completions.contains(QLatin1String("bar"))); +} + +void CppToolsPlugin::test_completion_lambdaCalls_2() +{ + TestData data; + data.srcText = + "struct S { int bar; };\n" + "void foo()\n" + "{\n" + " @\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("[] { return new S; } ()->"); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 2); + QVERIFY(completions.contains(QLatin1String("S"))); + QVERIFY(completions.contains(QLatin1String("bar"))); +} + +void CppToolsPlugin::test_completion_lambdaCalls_3() +{ + TestData data; + data.srcText = + "struct S { int bar; };\n" + "void foo()\n" + "{\n" + " @\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("[]() ->S* { return new S; } ()->"); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 2); + QVERIFY(completions.contains(QLatin1String("S"))); + QVERIFY(completions.contains(QLatin1String("bar"))); +} + +void CppToolsPlugin::test_completion_lambdaCalls_4() +{ + TestData data; + data.srcText = + "struct S { int bar; };\n" + "void foo()\n" + "{\n" + " @\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("[]() throw() { return new S; } ()->"); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 2); + QVERIFY(completions.contains(QLatin1String("S"))); + QVERIFY(completions.contains(QLatin1String("bar"))); +} + +void CppToolsPlugin::test_completion_lambdaCalls_5() +{ + TestData data; + data.srcText = + "struct S { int bar; };\n" + "void foo()\n" + "{\n" + " @\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("[]() throw()->S* { return new S; } ()->"); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 2); + QVERIFY(completions.contains(QLatin1String("S"))); + QVERIFY(completions.contains(QLatin1String("bar"))); +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 7a5f2878bfc..118b4e83641 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -156,6 +156,13 @@ private slots: void test_completion_enum_inside_block_inside_function_QTCREATORBUG5456(); void test_completion_enum_inside_function_QTCREATORBUG5456(); + //lambda + void test_completion_lambdaCalls_1(); + void test_completion_lambdaCalls_2(); + void test_completion_lambdaCalls_3(); + void test_completion_lambdaCalls_4(); + void test_completion_lambdaCalls_5(); + void test_format_pointerdeclaration_in_simpledeclarations(); void test_format_pointerdeclaration_in_simpledeclarations_data(); void test_format_pointerdeclaration_in_controlflowstatements();