diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp index baab83ef..4ae37f1d 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.cpp @@ -310,7 +310,33 @@ bool CxxAstVisitor::TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc return base::TraverseTemplateArgumentLoc(loc); } -void CxxAstVisitor::traverseDeclContextHelper(clang::DeclContext *d) +bool CxxAstVisitor::TraverseLambdaCapture(clang::LambdaExpr *lambdaExpr, const clang::LambdaCapture *capture) +{ + clang::VarDecl* d = capture->getCapturedVar(); + if (lambdaExpr->isInitCapture(capture)) + { + TraverseDecl(d); + } + else + { + SymbolKind symbolKind = getSymbolKind(d); + if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER) + { + if (!d->getNameAsString().empty()) // don't record anonymous parameters + { + ParseLocation declLocation = getParseLocation(d->getLocation()); + std::string name = + declLocation.filePath.fileName() + "<" + + std::to_string(declLocation.startLineNumber) + ":" + + std::to_string(declLocation.startColumnNumber) + ">"; + m_client->onLocalSymbolParsed(name, getParseLocation(capture->getLocation())); + } + } + } + return true; +} + +void CxxAstVisitor::traverseDeclContextHelper(clang::DeclContext* d) { if (!d) return; @@ -444,28 +470,7 @@ bool CxxAstVisitor::VisitVarDecl(clang::VarDecl* d) { if (shouldVisitDecl(d)) { - SymbolKind symbolKind = SYMBOL_KIND_MAX; - - if (llvm::isa(d)) - { - symbolKind = SYMBOL_PARAMETER; - } - else if (d->getParentFunctionOrMethod() == NULL) - { - if (d->getAccess() == clang::AS_none) - { - symbolKind = SYMBOL_GLOBAL_VARIABLE; - } - else - { - symbolKind = SYMBOL_FIELD; - } - } - else - { - symbolKind = SYMBOL_LOCAL_VARIABLE; - } - + SymbolKind symbolKind = getSymbolKind(d); if (symbolKind == SYMBOL_LOCAL_VARIABLE || symbolKind == SYMBOL_PARAMETER) { if (!d->getNameAsString().empty()) // don't record anonymous parameters @@ -1225,3 +1230,30 @@ ReferenceKind CxxAstVisitor::consumeDeclRefContextKind() } return refKind; } + +SymbolKind CxxAstVisitor::getSymbolKind(clang::VarDecl* d) +{ + SymbolKind symbolKind = SYMBOL_KIND_MAX; + + if (llvm::isa(d)) + { + symbolKind = SYMBOL_PARAMETER; + } + else if (d->getParentFunctionOrMethod() == NULL) + { + if (d->getAccess() == clang::AS_none) + { + symbolKind = SYMBOL_GLOBAL_VARIABLE; + } + else + { + symbolKind = SYMBOL_FIELD; + } + } + else + { + symbolKind = SYMBOL_LOCAL_VARIABLE; + } + + return symbolKind; +} diff --git a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h index 8336548d..73dddbe8 100644 --- a/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h +++ b/src/lib_cxx/data/parser/cxx/CxxAstVisitor.h @@ -83,7 +83,8 @@ public: virtual bool TraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc); virtual bool TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* s); virtual bool TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& loc); - void traverseDeclContextHelper(clang::DeclContext *d); + virtual bool TraverseLambdaCapture(clang::LambdaExpr* lambdaExpr, const clang::LambdaCapture* capture); + void traverseDeclContextHelper(clang::DeclContext* d); bool TraverseCallCommon(clang::CallExpr* s); // Visitor methods. These actually record stuff and store it in the database. @@ -129,6 +130,7 @@ protected: private: ReferenceKind consumeDeclRefContextKind(); + SymbolKind getSymbolKind(clang::VarDecl* d); typedef clang::RecursiveASTVisitor base; diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 9c227cc3..4f55fa48 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -933,6 +933,20 @@ public: TS_ASSERT_EQUALS(client->functions[1], "int lambdaWrapper::lambda at 3:2(int) <3:14 <3:2 3:2> 3:36>"); } + void test_cxx_parser_finds_local_variable_declared_in_lambda_capture() + { + std::shared_ptr client = parseCode( + "void lambdaWrapper()\n" + "{\n" + " [x(42)]() { return x; };\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->localSymbols.size(), 2); + TS_ASSERT_EQUALS(client->localSymbols[0], "input.cc<3:3> <3:3 3:3>"); + TS_ASSERT_EQUALS(client->localSymbols[1], "input.cc<3:3> <3:21 3:21>"); + } + void test_cxx_parser_finds_definition_of_local_symbol_in_function_parameter_list() { std::shared_ptr client = parseCode( @@ -2940,6 +2954,21 @@ public: TS_ASSERT_EQUALS(client->calls[1], "void lambdaCaller::lambda at 4:2() const -> void func() <6:3 6:6>"); } + void test_cxx_parser_finds_local_variable_in_lambda_capture() + { + std::shared_ptr client = parseCode( + "void lambdaWrapper()\n" + "{\n" + " int x = 2;\n" + " [x]() { return 1; }();\n" + "}\n" + ); + + TS_ASSERT_EQUALS(client->localSymbols.size(), 2); + TS_ASSERT_EQUALS(client->localSymbols[0], "input.cc<3:6> <3:6 3:6>"); + TS_ASSERT_EQUALS(client->localSymbols[1], "input.cc<3:6> <4:3 4:3>"); + } + void test_cxx_parser_finds_template_argument_of_unresolved_lookup_expression_as_type_use() { std::shared_ptr client = parseCode(