forked from OSchip/llvm-project
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
This commit is contained in:
parent
3405237f77
commit
5c2c60d2fc
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
NamedDecl *CallOp = Calls.front();
|
||||
FunctionTemplateDecl* CXXRecordDecl::getDependentLambdaCallOperator() const {
|
||||
NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
|
||||
return dyn_cast<FunctionTemplateDecl>(CallOp);
|
||||
}
|
||||
|
||||
CXXMethodDecl *CXXRecordDecl::getLambdaCallOperator() const {
|
||||
NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
|
||||
if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp))
|
||||
return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 $}}
|
||||
|
|
Loading…
Reference in New Issue