diff options
author | Erich Keane <erich.keane@intel.com> | 2019-09-30 19:12:29 +0000 |
---|---|---|
committer | Erich Keane <erich.keane@intel.com> | 2019-09-30 19:12:29 +0000 |
commit | 5c2c60d2fc27e57c56674205faf95ecf01c1d4d9 (patch) | |
tree | ae5e9ff8790dee900b4ec2032fa5acc9f29c3816 | |
parent | 3405237f77111946db90d986f2b5d9b9f8cae8a1 (diff) | |
download | bcm5719-llvm-5c2c60d2fc27e57c56674205faf95ecf01c1d4d9.tar.gz bcm5719-llvm-5c2c60d2fc27e57c56674205faf95ecf01c1d4d9.zip |
Teach CallGraph to look into Generic Lambdas.
CallGraph visited LambdaExpr by getting the Call Operator from
CXXRecordDecl (LambdaExpr::getCallOperator calls
CXXRecordDecl::getLambdaCallOperator), which replaced generic lambda
call operators with the non-instantiated FunctionDecl. The result was
that the CallGraph would only pick up non-dependent calls.
This patch does a few things:
1- Extend CXXRecordDecl to have a getDependentLambdaCallOperator, which
will get the FunctionTemplateDecl, rather than immediately getting the
TemplateDecl.
2- Define getLambdaCallOperator and getDependentLambdaCallOperator in
terms of a common function.
3- Extend LambdaExpr with a getDependentCallOperator, which just calls
the above function.
4- Changes CallGraph to handle Generic LambdaExprs.
llvm-svn: 373247
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 4 | ||||
-rw-r--r-- | clang/include/clang/AST/ExprCXX.h | 4 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 18 | ||||
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Analysis/CallGraph.cpp | 5 | ||||
-rw-r--r-- | clang/test/Analysis/debug-CallGraph.cpp | 21 |
6 files changed, 49 insertions, 8 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 0b835ecd736..de0aa5f9b90 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1172,6 +1172,10 @@ public: /// if this is a closure type. CXXMethodDecl *getLambdaCallOperator() const; + /// Retrieve the dependent lambda call operator of the closure type + /// if this is a templated closure type. + FunctionTemplateDecl *getDependentLambdaCallOperator() const; + /// Retrieve the lambda static invoker, the address of which /// is returned by the conversion operator, and the body of which /// is forwarded to the lambda call operator. diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index bc7d7c0a320..8e13eb5fdba 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1907,6 +1907,10 @@ public: /// lambda expression. CXXMethodDecl *getCallOperator() const; + /// Retrieve the function template call operator associated with this + /// lambda expression. + FunctionTemplateDecl *getDependentCallOperator() const; + /// If this is a generic lambda expression, retrieve the template /// parameter list associated with it, or else return null. TemplateParameterList *getTemplateParameterList() const; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 297a598911d..942588f4ede 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1399,17 +1399,25 @@ static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) { } #endif -CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const { - if (!isLambda()) return nullptr; +NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) { + if (!RD.isLambda()) return nullptr; DeclarationName Name = - getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); - DeclContext::lookup_result Calls = lookup(Name); + RD.getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); + DeclContext::lookup_result Calls = RD.lookup(Name); assert(!Calls.empty() && "Missing lambda call operator!"); assert(allLookupResultsAreTheSame(Calls) && "More than one lambda call operator!"); + return Calls.front(); +} + +FunctionTemplateDecl* CXXRecordDecl::getDependentLambdaCallOperator() const { + NamedDecl *CallOp = getLambdaCallOperatorHelper(*this); + return dyn_cast<FunctionTemplateDecl>(CallOp); +} - NamedDecl *CallOp = Calls.front(); +CXXMethodDecl *CXXRecordDecl::getLambdaCallOperator() const { + NamedDecl *CallOp = getLambdaCallOperatorHelper(*this); if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp)) return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl()); diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 30c28314d5b..1d5fd80d0d4 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1218,6 +1218,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const { return Record->getLambdaCallOperator(); } +FunctionTemplateDecl *LambdaExpr::getDependentCallOperator() const { + CXXRecordDecl *Record = getLambdaClass(); + return Record->getDependentLambdaCallOperator(); +} + TemplateParameterList *LambdaExpr::getTemplateParameterList() const { CXXRecordDecl *Record = getLambdaClass(); return Record->getGenericLambdaTemplateParameterList(); diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp index 865840eb341..76be292dad8 100644 --- a/clang/lib/Analysis/CallGraph.cpp +++ b/clang/lib/Analysis/CallGraph.cpp @@ -80,7 +80,10 @@ public: } void VisitLambdaExpr(LambdaExpr *LE) { - if (CXXMethodDecl *MD = LE->getCallOperator()) + if (FunctionTemplateDecl *FTD = LE->getDependentCallOperator()) + for (FunctionDecl *FD : FTD->specializations()) + G->VisitFunctionDecl(FD); + else if (CXXMethodDecl *MD = LE->getCallOperator()) G->VisitFunctionDecl(MD); } diff --git a/clang/test/Analysis/debug-CallGraph.cpp b/clang/test/Analysis/debug-CallGraph.cpp index 1d6844fad94..0f5a83b268a 100644 --- a/clang/test/Analysis/debug-CallGraph.cpp +++ b/clang/test/Analysis/debug-CallGraph.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s -fblocks 2>&1 | FileCheck %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s -fblocks -std=c++14 2>&1 | FileCheck %s int get5() { return 5; @@ -68,8 +68,25 @@ void templUser() { } } +namespace Lambdas { + void Callee(){} + + void f1() { + [](int i) { + Callee(); + }(1); + [](auto i) { + Callee(); + }(1); + } +} + // CHECK:--- Call graph Dump --- -// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser $}} +// CHECK-NEXT: {{Function: < root > calls: get5 add test_add mmm foo aaa < > bbb ddd ccc eee fff do_nothing test_single_call SomeNS::templ SomeNS::templ SomeNS::templUser Lambdas::Callee Lambdas::f1 Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) $}} +// CHECK-NEXT: {{Function: Lambdas::f1 calls: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) $}} +// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}} +// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}} +// CHECK-NEXT: {{Function: Lambdas::Callee calls: $}} // CHECK-NEXT: {{Function: SomeNS::templUser calls: SomeNS::templ SomeNS::templ $}} // CHECK-NEXT: {{Function: SomeNS::templ calls: eee $}} // CHECK-NEXT: {{Function: SomeNS::templ calls: ccc $}} |