| 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 | |