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(D: FD) && FD->isThisDeclarationADefinition()) { |
116 | // Add all blocks declared inside this function to the graph. |
117 | addNodesForBlocks(D: 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(D: FD, IsGlobal: FD->isGlobal()); |
122 | } |
123 | return true; |
124 | } |
125 | |
126 | /// Part of recursive declaration visitation. |
127 | bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { |
128 | if (includeInGraph(D: MD)) { |
129 | addNodesForBlocks(D: MD); |
130 | addNodeForDecl(D: MD, IsGlobal: 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(x: begin(), y: end()); |
185 | } |
186 | llvm::iterator_range<const_iterator> callees() const { |
187 | return llvm::make_range(x: begin(), y: 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(Elt: 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(PtrVal: 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 |
318 | |