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 |