1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | #ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H |
18 | #define LLVM_CLANG_ANALYSIS_CALLGRAPH_H |
19 | |
20 | #include "clang/AST/Decl.h" |
21 | #include "clang/AST/RecursiveASTVisitor.h" |
22 | #include "llvm/ADT/DenseMap.h" |
23 | #include "llvm/ADT/GraphTraits.h" |
24 | #include "llvm/ADT/STLExtras.h" |
25 | #include "llvm/ADT/SetVector.h" |
26 | #include "llvm/ADT/SmallVector.h" |
27 | #include <memory> |
28 | |
29 | namespace clang { |
30 | |
31 | class CallGraphNode; |
32 | class Decl; |
33 | class DeclContext; |
34 | class Stmt; |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | class CallGraph : public RecursiveASTVisitor<CallGraph> { |
42 | friend class CallGraphNode; |
43 | |
44 | using FunctionMapTy = |
45 | llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>; |
46 | |
47 | |
48 | FunctionMapTy FunctionMap; |
49 | |
50 | |
51 | CallGraphNode *Root; |
52 | |
53 | public: |
54 | CallGraph(); |
55 | ~CallGraph(); |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | void addToCallGraph(Decl *D) { |
62 | TraverseDecl(D); |
63 | } |
64 | |
65 | |
66 | static bool includeInGraph(const Decl *D); |
67 | |
68 | |
69 | CallGraphNode *getNode(const Decl *) const; |
70 | |
71 | |
72 | |
73 | CallGraphNode *getOrInsertNode(Decl *); |
74 | |
75 | using iterator = FunctionMapTy::iterator; |
76 | using const_iterator = FunctionMapTy::const_iterator; |
77 | |
78 | |
79 | |
80 | iterator begin() { return FunctionMap.begin(); } |
81 | iterator end() { return FunctionMap.end(); } |
82 | const_iterator begin() const { return FunctionMap.begin(); } |
83 | const_iterator end() const { return FunctionMap.end(); } |
84 | |
85 | |
86 | unsigned size() const { return FunctionMap.size(); } |
87 | |
88 | |
89 | |
90 | CallGraphNode *getRoot() const { return Root; } |
91 | |
92 | |
93 | |
94 | |
95 | using nodes_iterator = llvm::SetVector<CallGraphNode *>::iterator; |
96 | using const_nodes_iterator = llvm::SetVector<CallGraphNode *>::const_iterator; |
97 | |
98 | void print(raw_ostream &os) const; |
99 | void dump() const; |
100 | void viewGraph() const; |
101 | |
102 | void addNodesForBlocks(DeclContext *D); |
103 | |
104 | |
105 | |
106 | bool VisitFunctionDecl(FunctionDecl *FD) { |
107 | |
108 | |
109 | if (includeInGraph(FD) && FD->isThisDeclarationADefinition()) { |
110 | |
111 | addNodesForBlocks(FD); |
112 | |
113 | |
114 | |
115 | addNodeForDecl(FD, FD->isGlobal()); |
116 | } |
117 | return true; |
118 | } |
119 | |
120 | |
121 | bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { |
122 | if (includeInGraph(MD)) { |
123 | addNodesForBlocks(MD); |
124 | addNodeForDecl(MD, true); |
125 | } |
126 | return true; |
127 | } |
128 | |
129 | |
130 | bool TraverseStmt(Stmt *S) { return true; } |
131 | |
132 | bool shouldWalkTypesOfTypeLocs() const { return false; } |
133 | bool shouldVisitTemplateInstantiations() const { return true; } |
134 | |
135 | private: |
136 | |
137 | void addNodeForDecl(Decl *D, bool IsGlobal); |
138 | |
139 | |
140 | CallGraphNode *allocateNewNode(Decl *); |
141 | }; |
142 | |
143 | class CallGraphNode { |
144 | public: |
145 | using CallRecord = CallGraphNode *; |
146 | |
147 | private: |
148 | |
149 | Decl *FD; |
150 | |
151 | |
152 | SmallVector<CallRecord, 5> CalledFunctions; |
153 | |
154 | public: |
155 | CallGraphNode(Decl *D) : FD(D) {} |
156 | |
157 | using iterator = SmallVectorImpl<CallRecord>::iterator; |
158 | using const_iterator = SmallVectorImpl<CallRecord>::const_iterator; |
159 | |
160 | |
161 | iterator begin() { return CalledFunctions.begin(); } |
162 | iterator end() { return CalledFunctions.end(); } |
163 | const_iterator begin() const { return CalledFunctions.begin(); } |
164 | const_iterator end() const { return CalledFunctions.end(); } |
165 | |
166 | bool empty() const { return CalledFunctions.empty(); } |
167 | unsigned size() const { return CalledFunctions.size(); } |
168 | |
169 | void addCallee(CallGraphNode *N) { |
170 | CalledFunctions.push_back(N); |
171 | } |
172 | |
173 | Decl *getDecl() const { return FD; } |
174 | |
175 | void print(raw_ostream &os) const; |
176 | void dump() const; |
177 | }; |
178 | |
179 | } |
180 | |
181 | |
182 | namespace llvm { |
183 | |
184 | template <> struct GraphTraits<clang::CallGraphNode*> { |
185 | using NodeType = clang::CallGraphNode; |
186 | using NodeRef = clang::CallGraphNode *; |
187 | using ChildIteratorType = NodeType::iterator; |
188 | |
189 | static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; } |
190 | static ChildIteratorType child_begin(NodeType *N) { return N->begin(); } |
191 | static ChildIteratorType child_end(NodeType *N) { return N->end(); } |
192 | }; |
193 | |
194 | template <> struct GraphTraits<const clang::CallGraphNode*> { |
195 | using NodeType = const clang::CallGraphNode; |
196 | using NodeRef = const clang::CallGraphNode *; |
197 | using ChildIteratorType = NodeType::const_iterator; |
198 | |
199 | static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; } |
200 | static ChildIteratorType child_begin(NodeType *N) { return N->begin();} |
201 | static ChildIteratorType child_end(NodeType *N) { return N->end(); } |
202 | }; |
203 | |
204 | template <> struct GraphTraits<clang::CallGraph*> |
205 | : public GraphTraits<clang::CallGraphNode*> { |
206 | static NodeType *getEntryNode(clang::CallGraph *CGN) { |
207 | return CGN->getRoot(); |
208 | } |
209 | |
210 | static clang::CallGraphNode * |
211 | CGGetValue(clang::CallGraph::const_iterator::value_type &P) { |
212 | return P.second.get(); |
213 | } |
214 | |
215 | |
216 | using nodes_iterator = |
217 | mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)>; |
218 | |
219 | static nodes_iterator nodes_begin(clang::CallGraph *CG) { |
220 | return nodes_iterator(CG->begin(), &CGGetValue); |
221 | } |
222 | |
223 | static nodes_iterator nodes_end (clang::CallGraph *CG) { |
224 | return nodes_iterator(CG->end(), &CGGetValue); |
225 | } |
226 | |
227 | static unsigned size(clang::CallGraph *CG) { return CG->size(); } |
228 | }; |
229 | |
230 | template <> struct GraphTraits<const clang::CallGraph*> : |
231 | public GraphTraits<const clang::CallGraphNode*> { |
232 | static NodeType *getEntryNode(const clang::CallGraph *CGN) { |
233 | return CGN->getRoot(); |
234 | } |
235 | |
236 | static clang::CallGraphNode * |
237 | CGGetValue(clang::CallGraph::const_iterator::value_type &P) { |
238 | return P.second.get(); |
239 | } |
240 | |
241 | |
242 | using nodes_iterator = |
243 | mapped_iterator<clang::CallGraph::const_iterator, decltype(&CGGetValue)>; |
244 | |
245 | static nodes_iterator nodes_begin(const clang::CallGraph *CG) { |
246 | return nodes_iterator(CG->begin(), &CGGetValue); |
247 | } |
248 | |
249 | static nodes_iterator nodes_end(const clang::CallGraph *CG) { |
250 | return nodes_iterator(CG->end(), &CGGetValue); |
251 | } |
252 | |
253 | static unsigned size(const clang::CallGraph *CG) { return CG->size(); } |
254 | }; |
255 | |
256 | } |
257 | |
258 | #endif |
259 | |