Skip to content

Commit bee81d3

Browse files
Erich KeanehaoNoQ
authored andcommitted
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 (cherry picked from commit 5c2c60d)
1 parent 8bb333a commit bee81d3

File tree

6 files changed

+49
-8
lines changed

6 files changed

+49
-8
lines changed

clang/include/clang/AST/DeclCXX.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,10 @@ class CXXRecordDecl : public RecordDecl {
12121212
/// if this is a closure type.
12131213
CXXMethodDecl *getLambdaCallOperator() const;
12141214

1215+
/// Retrieve the dependent lambda call operator of the closure type
1216+
/// if this is a templated closure type.
1217+
FunctionTemplateDecl *getDependentLambdaCallOperator() const;
1218+
12151219
/// Retrieve the lambda static invoker, the address of which
12161220
/// is returned by the conversion operator, and the body of which
12171221
/// is forwarded to the lambda call operator.

clang/include/clang/AST/ExprCXX.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,6 +1902,10 @@ class LambdaExpr final : public Expr,
19021902
/// lambda expression.
19031903
CXXMethodDecl *getCallOperator() const;
19041904

1905+
/// Retrieve the function template call operator associated with this
1906+
/// lambda expression.
1907+
FunctionTemplateDecl *getDependentCallOperator() const;
1908+
19051909
/// If this is a generic lambda expression, retrieve the template
19061910
/// parameter list associated with it, or else return null.
19071911
TemplateParameterList *getTemplateParameterList() const;

clang/lib/AST/DeclCXX.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,17 +1369,25 @@ static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
13691369
}
13701370
#endif
13711371

1372-
CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
1373-
if (!isLambda()) return nullptr;
1372+
NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
1373+
if (!RD.isLambda()) return nullptr;
13741374
DeclarationName Name =
1375-
getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
1376-
DeclContext::lookup_result Calls = lookup(Name);
1375+
RD.getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
1376+
DeclContext::lookup_result Calls = RD.lookup(Name);
13771377

13781378
assert(!Calls.empty() && "Missing lambda call operator!");
13791379
assert(allLookupResultsAreTheSame(Calls) &&
13801380
"More than one lambda call operator!");
1381+
return Calls.front();
1382+
}
1383+
1384+
FunctionTemplateDecl* CXXRecordDecl::getDependentLambdaCallOperator() const {
1385+
NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
1386+
return dyn_cast<FunctionTemplateDecl>(CallOp);
1387+
}
13811388

1382-
NamedDecl *CallOp = Calls.front();
1389+
CXXMethodDecl *CXXRecordDecl::getLambdaCallOperator() const {
1390+
NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
13831391
if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp))
13841392
return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
13851393

clang/lib/AST/ExprCXX.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
12051205
return Record->getLambdaCallOperator();
12061206
}
12071207

1208+
FunctionTemplateDecl *LambdaExpr::getDependentCallOperator() const {
1209+
CXXRecordDecl *Record = getLambdaClass();
1210+
return Record->getDependentLambdaCallOperator();
1211+
}
1212+
12081213
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
12091214
CXXRecordDecl *Record = getLambdaClass();
12101215
return Record->getGenericLambdaTemplateParameterList();

clang/lib/Analysis/CallGraph.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,10 @@ class CGBuilder : public StmtVisitor<CGBuilder> {
8080
}
8181

8282
void VisitLambdaExpr(LambdaExpr *LE) {
83-
if (CXXMethodDecl *MD = LE->getCallOperator())
83+
if (FunctionTemplateDecl *FTD = LE->getDependentCallOperator())
84+
for (FunctionDecl *FD : FTD->specializations())
85+
G->VisitFunctionDecl(FD);
86+
else if (CXXMethodDecl *MD = LE->getCallOperator())
8487
G->VisitFunctionDecl(MD);
8588
}
8689

clang/test/Analysis/debug-CallGraph.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s -fblocks 2>&1 | FileCheck %s
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s -fblocks -std=c++14 2>&1 | FileCheck %s
22

33
int get5() {
44
return 5;
@@ -68,8 +68,25 @@ void templUser() {
6868
}
6969
}
7070

71+
namespace Lambdas {
72+
void Callee(){}
73+
74+
void f1() {
75+
[](int i) {
76+
Callee();
77+
}(1);
78+
[](auto i) {
79+
Callee();
80+
}(1);
81+
}
82+
}
83+
7184
// CHECK:--- Call graph Dump ---
72-
// 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 $}}
85+
// 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\(\) $}}
86+
// CHECK-NEXT: {{Function: Lambdas::f1 calls: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) Lambdas::f1\(\)::\(anonymous class\)::operator\(\) $}}
87+
// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}}
88+
// CHECK-NEXT: {{Function: Lambdas::f1\(\)::\(anonymous class\)::operator\(\) calls: Lambdas::Callee $}}
89+
// CHECK-NEXT: {{Function: Lambdas::Callee calls: $}}
7390
// CHECK-NEXT: {{Function: SomeNS::templUser calls: SomeNS::templ SomeNS::templ $}}
7491
// CHECK-NEXT: {{Function: SomeNS::templ calls: eee $}}
7592
// CHECK-NEXT: {{Function: SomeNS::templ calls: ccc $}}

0 commit comments

Comments
 (0)