Skip to content

Commit bee81d3

Browse files
Erich KeanehaoNoQ
Erich Keane
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

+4
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

+4
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

+13-5
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

+5
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

+4-1
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

+19-2
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)