clang-tools 8.0.0

HelperDeclRefGraph.cpp
Go to the documentation of this file.
1 //===-- UsedHelperDeclFinder.cpp - AST-based call graph for helper decls --===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "HelperDeclRefGraph.h"
11 #include "ClangMove.h"
12 #include "clang/AST/Decl.h"
13 #include "llvm/Support/Debug.h"
14 #include <vector>
15
16 #define DEBUG_TYPE "clang-move"
17
18 namespace clang {
19 namespace move {
20
21 void HelperDeclRefGraph::print(raw_ostream &OS) const {
22 OS << " --- Call graph Dump --- \n";
23 for (auto I = DeclMap.begin(); I != DeclMap.end(); ++I) {
24 const CallGraphNode *N = (I->second).get();
25
26 OS << " Declarations: ";
27 N->print(OS);
28 OS << " (" << N << ") ";
29 OS << " calls: ";
30 for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {
31 (*CI)->print(OS);
32 OS << " (" << CI << ") ";
33 }
34 OS << '\n';
35 }
36 OS.flush();
37 }
38
39 void HelperDeclRefGraph::addEdge(const Decl *Caller, const Decl *Callee) {
40 assert(Caller);
41 assert(Callee);
42
43 // Ignore the case where Caller equals Callee. This happens in the static
44 // class member definitions in global namespace like "int CLASS::static_var =
45 // 1;", its DC is a VarDel whose outmost enclosing declaration is the "CLASS"
46 // CXXRecordDecl.
47 if (Caller == Callee) return;
48
49 // Allocate a new node, mark it as root, and process it's calls.
50 CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));
51 CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));
52 CallerNode->addCallee(CalleeNode);
53 }
54
55 void HelperDeclRefGraph::dump() const { print(llvm::errs()); }
56
57 CallGraphNode *HelperDeclRefGraph::getOrInsertNode(Decl *F) {
58 F = F->getCanonicalDecl();
59 std::unique_ptr<CallGraphNode> &Node = DeclMap[F];
60 if (Node)
61 return Node.get();
62
63 Node = llvm::make_unique<CallGraphNode>(F);
64 return Node.get();
65 }
66
67 CallGraphNode *HelperDeclRefGraph::getNode(const Decl *D) const {
68 auto I = DeclMap.find(D->getCanonicalDecl());
69 return I == DeclMap.end() ? nullptr : I->second.get();
70 }
71
72 llvm::DenseSet<const CallGraphNode *>
73 HelperDeclRefGraph::getReachableNodes(const Decl *Root) const {
74 const auto *RootNode = getNode(Root);
75 if (!RootNode)
76 return {};
77 llvm::DenseSet<const CallGraphNode *> ConnectedNodes;
78 std::function<void(const CallGraphNode *)> VisitNode =
79 [&](const CallGraphNode *Node) {
80 if (ConnectedNodes.count(Node))
81 return;
82 ConnectedNodes.insert(Node);
83 for (auto It = Node->begin(), End = Node->end(); It != End; ++It)
84 VisitNode(*It);
85 };
86
87 VisitNode(RootNode);
88 return ConnectedNodes;
89 }
90
91 const Decl *HelperDeclRGBuilder::getOutmostClassOrFunDecl(const Decl *D) {
92 const auto *DC = D->getDeclContext();
93 const auto *Result = D;
94 while (DC) {
95 if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
96 Result = RD;
97 else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
98 Result = FD;
99 DC = DC->getParent();
100 }
101 return Result;
102 }
103
104 void HelperDeclRGBuilder::run(
105 const ast_matchers::MatchFinder::MatchResult &Result) {
106 // Construct the graph by adding a directed edge from caller to callee.
107 //
108 // "dc" is the closest ancestor declaration of "func_ref" or "used_class", it
109 // might be not the targetted Caller Decl, we always use the outmost enclosing
110 // FunctionDecl/CXXRecordDecl of "dc". For example,
111 //
112 // int MoveClass::F() { int a = helper(); return a; }
113 //
114 // The matched "dc" of "helper" DeclRefExpr is a VarDecl, we traverse up AST
115 // to find the outmost "MoveClass" CXXRecordDecl and use it as Caller.
116 if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
117 const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
118 assert(DC);
119 LLVM_DEBUG(llvm::dbgs() << "Find helper function usage: "
120 << FuncRef->getDecl()->getNameAsString() << " ("
121 << FuncRef->getDecl() << ")\n");
122 RG->addEdge(
123 getOutmostClassOrFunDecl(DC->getCanonicalDecl()),
124 getOutmostClassOrFunDecl(FuncRef->getDecl()->getCanonicalDecl()));
125 } else if (const auto *UsedClass =
126 Result.Nodes.getNodeAs<CXXRecordDecl>("used_class")) {
127 const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
128 assert(DC);
129 LLVM_DEBUG(llvm::dbgs()
130 << "Find helper class usage: " << UsedClass->getNameAsString()
131 << " (" << UsedClass << ")\n");
132 RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass);
133 }
134 }
135
136 } // namespace move
137 } // namespace clang
clang::move::HelperDeclRefGraph::getReachableNodes
llvm::DenseSet< const CallGraphNode * > getReachableNodes(const Decl *D) const
Definition: HelperDeclRefGraph.cpp:73
clang::move::HelperDeclRefGraph::addEdge
void addEdge(const Decl *Caller, const Decl *Callee)
Definition: HelperDeclRefGraph.cpp:39
clang::move::HelperDeclRGBuilder::getOutmostClassOrFunDecl
static const Decl * getOutmostClassOrFunDecl(const Decl *D)
Definition: HelperDeclRefGraph.cpp:91
ClangMove.h
D
const Decl * D
Definition: XRefs.cpp:79
clang::move::HelperDeclRefGraph::dump
void dump() const
Definition: HelperDeclRefGraph.cpp:55
Result
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: ClangdServer.cpp:60
clang::move::HelperDeclRefGraph::getNode
CallGraphNode * getNode(const Decl *D) const
Definition: HelperDeclRefGraph.cpp:67
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::move::HelperDeclRGBuilder::run
void run(const ast_matchers::MatchFinder::MatchResult &Result) override
Definition: HelperDeclRefGraph.cpp:104
HelperDeclRefGraph.h