Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- CallGraph.h - AST-based Call graph -----------------------*- C++ -*-===// |
2 | // |
||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
4 | // See https://llvm.org/LICENSE.txt for license information. |
||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
6 | // |
||
7 | //===----------------------------------------------------------------------===// |
||
8 | // |
||
9 | // This file declares the AST-based CallGraph. |
||
10 | // |
||
11 | // A call graph for functions whose definitions/bodies are available in the |
||
12 | // current translation unit. The graph has a "virtual" root node that contains |
||
13 | // edges to all externally available functions. |
||
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 "llvm/ADT/iterator_range.h" |
||
28 | #include <memory> |
||
29 | |||
30 | namespace clang { |
||
31 | |||
32 | class CallGraphNode; |
||
33 | class Decl; |
||
34 | class DeclContext; |
||
35 | class Stmt; |
||
36 | |||
37 | /// The AST-based call graph. |
||
38 | /// |
||
39 | /// The call graph extends itself with the given declarations by implementing |
||
40 | /// the recursive AST visitor, which constructs the graph by visiting the given |
||
41 | /// declarations. |
||
42 | class CallGraph : public RecursiveASTVisitor<CallGraph> { |
||
43 | friend class CallGraphNode; |
||
44 | |||
45 | using FunctionMapTy = |
||
46 | llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>; |
||
47 | |||
48 | /// FunctionMap owns all CallGraphNodes. |
||
49 | FunctionMapTy FunctionMap; |
||
50 | |||
51 | /// This is a virtual root node that has edges to all the functions. |
||
52 | CallGraphNode *Root; |
||
53 | |||
54 | public: |
||
55 | CallGraph(); |
||
56 | ~CallGraph(); |
||
57 | |||
58 | /// Populate the call graph with the functions in the given |
||
59 | /// declaration. |
||
60 | /// |
||
61 | /// Recursively walks the declaration to find all the dependent Decls as well. |
||
62 | void addToCallGraph(Decl *D) { |
||
63 | TraverseDecl(D); |
||
64 | } |
||
65 | |||
66 | /// Determine if a declaration should be included in the graph. |
||
67 | static bool includeInGraph(const Decl *D); |
||
68 | |||
69 | /// Determine if a declaration should be included in the graph for the |
||
70 | /// purposes of being a callee. This is similar to includeInGraph except |
||
71 | /// it permits declarations, not just definitions. |
||
72 | static bool includeCalleeInGraph(const Decl *D); |
||
73 | |||
74 | /// Lookup the node for the given declaration. |
||
75 | CallGraphNode *getNode(const Decl *) const; |
||
76 | |||
77 | /// Lookup the node for the given declaration. If none found, insert |
||
78 | /// one into the graph. |
||
79 | CallGraphNode *getOrInsertNode(Decl *); |
||
80 | |||
81 | using iterator = FunctionMapTy::iterator; |
||
82 | using const_iterator = FunctionMapTy::const_iterator; |
||
83 | |||
84 | /// Iterators through all the elements in the graph. Note, this gives |
||
85 | /// non-deterministic order. |
||
86 | iterator begin() { return FunctionMap.begin(); } |
||
87 | iterator end() { return FunctionMap.end(); } |
||
88 | const_iterator begin() const { return FunctionMap.begin(); } |
||
89 | const_iterator end() const { return FunctionMap.end(); } |
||
90 | |||
91 | /// Get the number of nodes in the graph. |
||
92 | unsigned size() const { return FunctionMap.size(); } |
||
93 | |||
94 | /// Get the virtual root of the graph, all the functions available externally |
||
95 | /// are represented as callees of the node. |
||
96 | CallGraphNode *getRoot() const { return Root; } |
||
97 | |||
98 | /// Iterators through all the nodes of the graph that have no parent. These |
||
99 | /// are the unreachable nodes, which are either unused or are due to us |
||
100 | /// failing to add a call edge due to the analysis imprecision. |
||
101 | using nodes_iterator = llvm::SetVector<CallGraphNode *>::iterator; |
||
102 | using const_nodes_iterator = llvm::SetVector<CallGraphNode *>::const_iterator; |
||
103 | |||
104 | void print(raw_ostream &os) const; |
||
105 | void dump() const; |
||
106 | void viewGraph() const; |
||
107 | |||
108 | void addNodesForBlocks(DeclContext *D); |
||
109 | |||
110 | /// Part of recursive declaration visitation. We recursively visit all the |
||
111 | /// declarations to collect the root functions. |
||
112 | bool VisitFunctionDecl(FunctionDecl *FD) { |
||
113 | // We skip function template definitions, as their semantics is |
||
114 | // only determined when they are instantiated. |
||
115 | if (includeInGraph(FD) && FD->isThisDeclarationADefinition()) { |
||
116 | // Add all blocks declared inside this function to the graph. |
||
117 | addNodesForBlocks(FD); |
||
118 | // If this function has external linkage, anything could call it. |
||
119 | // Note, we are not precise here. For example, the function could have |
||
120 | // its address taken. |
||
121 | addNodeForDecl(FD, FD->isGlobal()); |
||
122 | } |
||
123 | return true; |
||
124 | } |
||
125 | |||
126 | /// Part of recursive declaration visitation. |
||
127 | bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { |
||
128 | if (includeInGraph(MD)) { |
||
129 | addNodesForBlocks(MD); |
||
130 | addNodeForDecl(MD, true); |
||
131 | } |
||
132 | return true; |
||
133 | } |
||
134 | |||
135 | // We are only collecting the declarations, so do not step into the bodies. |
||
136 | bool TraverseStmt(Stmt *S) { return true; } |
||
137 | |||
138 | bool shouldWalkTypesOfTypeLocs() const { return false; } |
||
139 | bool shouldVisitTemplateInstantiations() const { return true; } |
||
140 | bool shouldVisitImplicitCode() const { return true; } |
||
141 | |||
142 | private: |
||
143 | /// Add the given declaration to the call graph. |
||
144 | void addNodeForDecl(Decl *D, bool IsGlobal); |
||
145 | }; |
||
146 | |||
147 | class CallGraphNode { |
||
148 | public: |
||
149 | struct CallRecord { |
||
150 | CallGraphNode *Callee; |
||
151 | Expr *CallExpr; |
||
152 | |||
153 | CallRecord() = default; |
||
154 | |||
155 | CallRecord(CallGraphNode *Callee_, Expr *CallExpr_) |
||
156 | : Callee(Callee_), CallExpr(CallExpr_) {} |
||
157 | |||
158 | // The call destination is the only important data here, |
||
159 | // allow to transparently unwrap into it. |
||
160 | operator CallGraphNode *() const { return Callee; } |
||
161 | }; |
||
162 | |||
163 | private: |
||
164 | /// The function/method declaration. |
||
165 | Decl *FD; |
||
166 | |||
167 | /// The list of functions called from this node. |
||
168 | SmallVector<CallRecord, 5> CalledFunctions; |
||
169 | |||
170 | public: |
||
171 | CallGraphNode(Decl *D) : FD(D) {} |
||
172 | |||
173 | using iterator = SmallVectorImpl<CallRecord>::iterator; |
||
174 | using const_iterator = SmallVectorImpl<CallRecord>::const_iterator; |
||
175 | |||
176 | /// Iterators through all the callees/children of the node. |
||
177 | iterator begin() { return CalledFunctions.begin(); } |
||
178 | iterator end() { return CalledFunctions.end(); } |
||
179 | const_iterator begin() const { return CalledFunctions.begin(); } |
||
180 | const_iterator end() const { return CalledFunctions.end(); } |
||
181 | |||
182 | /// Iterator access to callees/children of the node. |
||
183 | llvm::iterator_range<iterator> callees() { |
||
184 | return llvm::make_range(begin(), end()); |
||
185 | } |
||
186 | llvm::iterator_range<const_iterator> callees() const { |
||
187 | return llvm::make_range(begin(), end()); |
||
188 | } |
||
189 | |||
190 | bool empty() const { return CalledFunctions.empty(); } |
||
191 | unsigned size() const { return CalledFunctions.size(); } |
||
192 | |||
193 | void addCallee(CallRecord Call) { CalledFunctions.push_back(Call); } |
||
194 | |||
195 | Decl *getDecl() const { return FD; } |
||
196 | |||
197 | FunctionDecl *getDefinition() const { |
||
198 | return getDecl()->getAsFunction()->getDefinition(); |
||
199 | } |
||
200 | |||
201 | void print(raw_ostream &os) const; |
||
202 | void dump() const; |
||
203 | }; |
||
204 | |||
205 | // NOTE: we are comparing based on the callee only. So different call records |
||
206 | // (with different call expressions) to the same callee will compare equal! |
||
207 | inline bool operator==(const CallGraphNode::CallRecord &LHS, |
||
208 | const CallGraphNode::CallRecord &RHS) { |
||
209 | return LHS.Callee == RHS.Callee; |
||
210 | } |
||
211 | |||
212 | } // namespace clang |
||
213 | |||
214 | namespace llvm { |
||
215 | |||
216 | // Specialize DenseMapInfo for clang::CallGraphNode::CallRecord. |
||
217 | template <> struct DenseMapInfo<clang::CallGraphNode::CallRecord> { |
||
218 | static inline clang::CallGraphNode::CallRecord getEmptyKey() { |
||
219 | return clang::CallGraphNode::CallRecord( |
||
220 | DenseMapInfo<clang::CallGraphNode *>::getEmptyKey(), |
||
221 | DenseMapInfo<clang::Expr *>::getEmptyKey()); |
||
222 | } |
||
223 | |||
224 | static inline clang::CallGraphNode::CallRecord getTombstoneKey() { |
||
225 | return clang::CallGraphNode::CallRecord( |
||
226 | DenseMapInfo<clang::CallGraphNode *>::getTombstoneKey(), |
||
227 | DenseMapInfo<clang::Expr *>::getTombstoneKey()); |
||
228 | } |
||
229 | |||
230 | static unsigned getHashValue(const clang::CallGraphNode::CallRecord &Val) { |
||
231 | // NOTE: we are comparing based on the callee only. |
||
232 | // Different call records with the same callee will compare equal! |
||
233 | return DenseMapInfo<clang::CallGraphNode *>::getHashValue(Val.Callee); |
||
234 | } |
||
235 | |||
236 | static bool isEqual(const clang::CallGraphNode::CallRecord &LHS, |
||
237 | const clang::CallGraphNode::CallRecord &RHS) { |
||
238 | return LHS == RHS; |
||
239 | } |
||
240 | }; |
||
241 | |||
242 | // Graph traits for iteration, viewing. |
||
243 | template <> struct GraphTraits<clang::CallGraphNode*> { |
||
244 | using NodeType = clang::CallGraphNode; |
||
245 | using NodeRef = clang::CallGraphNode *; |
||
246 | using ChildIteratorType = NodeType::iterator; |
||
247 | |||
248 | static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; } |
||
249 | static ChildIteratorType child_begin(NodeType *N) { return N->begin(); } |
||
250 | static ChildIteratorType child_end(NodeType *N) { return N->end(); } |
||
251 | }; |
||
252 | |||
253 | template <> struct GraphTraits<const clang::CallGraphNode*> { |
||
254 | using NodeType = const clang::CallGraphNode; |
||
255 | using NodeRef = const clang::CallGraphNode *; |
||
256 | using ChildIteratorType = NodeType::const_iterator; |
||
257 | |||
258 | static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; } |
||
259 | static ChildIteratorType child_begin(NodeType *N) { return N->begin();} |
||
260 | static ChildIteratorType child_end(NodeType *N) { return N->end(); } |
||
261 | }; |
||
262 | |||
263 | template <> struct GraphTraits<clang::CallGraph*> |
||
264 | : public GraphTraits<clang::CallGraphNode*> { |
||
265 | static NodeType *getEntryNode(clang::CallGraph *CGN) { |
||
266 | return CGN->getRoot(); // Start at the external node! |
||
267 | } |
||
268 | |||
269 | static clang::CallGraphNode * |
||
270 | CGGetValue(clang::CallGraph::const_iterator::value_type &P) { |
||
271 | return P.second.get(); |
||
272 | } |
||
273 | |||
274 | // nodes_iterator/begin/end - Allow iteration over all nodes in the graph |
||
275 | using nodes_iterator = |
||
276 | mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)>; |
||
277 | |||
278 | static nodes_iterator nodes_begin(clang::CallGraph *CG) { |
||
279 | return nodes_iterator(CG->begin(), &CGGetValue); |
||
280 | } |
||
281 | |||
282 | static nodes_iterator nodes_end (clang::CallGraph *CG) { |
||
283 | return nodes_iterator(CG->end(), &CGGetValue); |
||
284 | } |
||
285 | |||
286 | static unsigned size(clang::CallGraph *CG) { return CG->size(); } |
||
287 | }; |
||
288 | |||
289 | template <> struct GraphTraits<const clang::CallGraph*> : |
||
290 | public GraphTraits<const clang::CallGraphNode*> { |
||
291 | static NodeType *getEntryNode(const clang::CallGraph *CGN) { |
||
292 | return CGN->getRoot(); |
||
293 | } |
||
294 | |||
295 | static clang::CallGraphNode * |
||
296 | CGGetValue(clang::CallGraph::const_iterator::value_type &P) { |
||
297 | return P.second.get(); |
||
298 | } |
||
299 | |||
300 | // nodes_iterator/begin/end - Allow iteration over all nodes in the graph |
||
301 | using nodes_iterator = |
||
302 | mapped_iterator<clang::CallGraph::const_iterator, decltype(&CGGetValue)>; |
||
303 | |||
304 | static nodes_iterator nodes_begin(const clang::CallGraph *CG) { |
||
305 | return nodes_iterator(CG->begin(), &CGGetValue); |
||
306 | } |
||
307 | |||
308 | static nodes_iterator nodes_end(const clang::CallGraph *CG) { |
||
309 | return nodes_iterator(CG->end(), &CGGetValue); |
||
310 | } |
||
311 | |||
312 | static unsigned size(const clang::CallGraph *CG) { return CG->size(); } |
||
313 | }; |
||
314 | |||
315 | } // namespace llvm |
||
316 | |||
317 | #endif // LLVM_CLANG_ANALYSIS_CALLGRAPH_H |