mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 19:45:40 -04:00
[CallGraph] Take into accound calls that aren't within any function bodies.
This patch improves Clang call graph analysis by adding in expressions that are not found in regular function bodies, such as default arguments or member initializers. Patch by Joshua Cranmer! Differential Revision: https://reviews.llvm.org/D65453 llvm-svn: 369321
This commit is contained in:
parent
ee92f12fd1
commit
8cf3dfea54
@ -131,6 +131,7 @@ public:
|
|||||||
|
|
||||||
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
||||||
bool shouldVisitTemplateInstantiations() const { return true; }
|
bool shouldVisitTemplateInstantiations() const { return true; }
|
||||||
|
bool shouldVisitImplicitCode() const { return true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Add the given declaration to the call graph.
|
/// Add the given declaration to the call graph.
|
||||||
|
@ -79,6 +79,34 @@ public:
|
|||||||
VisitChildren(CE);
|
VisitChildren(CE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VisitLambdaExpr(LambdaExpr *LE) {
|
||||||
|
if (CXXMethodDecl *MD = LE->getCallOperator())
|
||||||
|
G->VisitFunctionDecl(MD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisitCXXNewExpr(CXXNewExpr *E) {
|
||||||
|
if (FunctionDecl *FD = E->getOperatorNew())
|
||||||
|
addCalledDecl(FD);
|
||||||
|
VisitChildren(E);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisitCXXConstructExpr(CXXConstructExpr *E) {
|
||||||
|
CXXConstructorDecl *Ctor = E->getConstructor();
|
||||||
|
if (FunctionDecl *Def = Ctor->getDefinition())
|
||||||
|
addCalledDecl(Def);
|
||||||
|
VisitChildren(E);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the evaluation of the default argument.
|
||||||
|
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
|
||||||
|
Visit(E->getExpr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the evaluation of the default initializers in a class.
|
||||||
|
void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
|
||||||
|
Visit(E->getExpr());
|
||||||
|
}
|
||||||
|
|
||||||
// Adds may-call edges for the ObjC message sends.
|
// Adds may-call edges for the ObjC message sends.
|
||||||
void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
|
void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
|
||||||
if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
|
if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
|
||||||
@ -143,13 +171,20 @@ bool CallGraph::includeInGraph(const Decl *D) {
|
|||||||
void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
|
void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
|
||||||
assert(D);
|
assert(D);
|
||||||
|
|
||||||
// Allocate a new node, mark it as root, and process it's calls.
|
// Allocate a new node, mark it as root, and process its calls.
|
||||||
CallGraphNode *Node = getOrInsertNode(D);
|
CallGraphNode *Node = getOrInsertNode(D);
|
||||||
|
|
||||||
// Process all the calls by this function as well.
|
// Process all the calls by this function as well.
|
||||||
CGBuilder builder(this, Node);
|
CGBuilder builder(this, Node);
|
||||||
if (Stmt *Body = D->getBody())
|
if (Stmt *Body = D->getBody())
|
||||||
builder.Visit(Body);
|
builder.Visit(Body);
|
||||||
|
|
||||||
|
// Include C++ constructor member initializers.
|
||||||
|
if (auto constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||||
|
for (CXXCtorInitializer *init : constructor->inits()) {
|
||||||
|
builder.Visit(init->getInit());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CallGraphNode *CallGraph::getNode(const Decl *F) const {
|
CallGraphNode *CallGraph::getNode(const Decl *F) const {
|
||||||
|
29
clang/test/Analysis/cxx-callgraph.cpp
Normal file
29
clang/test/Analysis/cxx-callgraph.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCallGraph %s 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
static int aaa() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bbb(int param=aaa()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ddd();
|
||||||
|
|
||||||
|
struct c {
|
||||||
|
c(int param=2) : val(bbb(param)) {}
|
||||||
|
int val;
|
||||||
|
int val2 = ddd();
|
||||||
|
};
|
||||||
|
|
||||||
|
int ddd() {
|
||||||
|
c c;
|
||||||
|
return bbb();
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK:--- Call graph Dump ---
|
||||||
|
// CHECK-NEXT: {{Function: < root > calls: aaa bbb c::c ddd}}
|
||||||
|
// CHECK-NEXT: {{Function: c::c calls: bbb ddd $}}
|
||||||
|
// CHECK-NEXT: {{Function: ddd calls: c::c bbb aaa $}}
|
||||||
|
// CHECK-NEXT: {{Function: bbb calls: $}}
|
||||||
|
// CHECK-NEXT: {{Function: aaa calls: $}}
|
@ -1,5 +1,6 @@
|
|||||||
// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
|
// FIXME: Figure out how to use %clang_analyze_cc1 with our lit.local.cfg.
|
||||||
// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
|
// RUN: %clang_cc1 -analyze -triple x86_64-unknown-linux-gnu \
|
||||||
|
// RUN: -analyze-function "test()" \
|
||||||
// RUN: -analyzer-checker=core \
|
// RUN: -analyzer-checker=core \
|
||||||
// RUN: -analyzer-dump-egraph=%t.dot %s
|
// RUN: -analyzer-dump-egraph=%t.dot %s
|
||||||
// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
|
// RUN: %exploded_graph_rewriter %t.dot | FileCheck %s
|
||||||
|
Loading…
Reference in New Issue
Block a user