Skip to content

Commit 5c2c60d

Browse files
author
Erich Keane
committed
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
1 parent 3405237 commit 5c2c60d

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
@@ -1172,6 +1172,10 @@ class CXXRecordDecl : public RecordDecl {
11721172
/// if this is a closure type.
11731173
CXXMethodDecl *getLambdaCallOperator() const;
11741174

1175+
/// Retrieve the dependent lambda call operator of the closure type
1176+
/// if this is a templated closure type.
1177+
FunctionTemplateDecl *getDependentLambdaCallOperator() const;
1178+
11751179
/// Retrieve the lambda static invoker, the address of which
11761180
/// is returned by the conversion operator, and the body of which
11771181
/// 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
@@ -1907,6 +1907,10 @@ class LambdaExpr final : public Expr,
19071907
/// lambda expression.
19081908
CXXMethodDecl *getCallOperator() const;
19091909

1910+
/// Retrieve the function template call operator associated with this
1911+
/// lambda expression.
1912+
FunctionTemplateDecl *getDependentCallOperator() const;
1913+
19101914
/// If this is a generic lambda expression, retrieve the template
19111915
/// parameter list associated with it, or else return null.
19121916
TemplateParameterList *getTemplateParameterList() const;

clang/lib/AST/DeclCXX.cpp

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

1402-
CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
1403-
if (!isLambda()) return nullptr;
1402+
NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
1403+
if (!RD.isLambda()) return nullptr;
14041404
DeclarationName Name =
1405-
getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
1406-
DeclContext::lookup_result Calls = lookup(Name);
1405+
RD.getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
1406+
DeclContext::lookup_result Calls = RD.lookup(Name);
14071407

14081408
assert(!Calls.empty() && "Missing lambda call operator!");
14091409
assert(allLookupResultsAreTheSame(Calls) &&
14101410
"More than one lambda call operator!");
1411+
return Calls.front();
1412+
}
1413+
1414+
FunctionTemplateDecl* CXXRecordDecl::getDependentLambdaCallOperator() const {
1415+
NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
1416+
return dyn_cast<FunctionTemplateDecl>(CallOp);
1417+
}
14111418

1412-
NamedDecl *CallOp = Calls.front();
1419+
CXXMethodDecl *CXXRecordDecl::getLambdaCallOperator() const {
1420+
NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
14131421
if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp))
14141422
return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
14151423

clang/lib/AST/ExprCXX.cpp

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

1221+
FunctionTemplateDecl *LambdaExpr::getDependentCallOperator() const {
1222+
CXXRecordDecl *Record = getLambdaClass();
1223+
return Record->getDependentLambdaCallOperator();
1224+
}
1225+
12211226
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
12221227
CXXRecordDecl *Record = getLambdaClass();
12231228
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)