xref: /llvm-project/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp (revision 0efd52487e95f18c88f9c55791d733efccb29079)
13626516bSHaojian Wu //===-- UsedHelperDeclFinder.cpp - AST-based call graph for helper decls --===//
23626516bSHaojian Wu //
33626516bSHaojian Wu //                     The LLVM Compiler Infrastructure
43626516bSHaojian Wu //
53626516bSHaojian Wu // This file is distributed under the University of Illinois Open Source
63626516bSHaojian Wu // License. See LICENSE.TXT for details.
73626516bSHaojian Wu //
83626516bSHaojian Wu //===----------------------------------------------------------------------===//
93626516bSHaojian Wu 
103626516bSHaojian Wu #include "HelperDeclRefGraph.h"
113626516bSHaojian Wu #include "ClangMove.h"
123626516bSHaojian Wu #include "clang/AST/Decl.h"
134775ce56SHaojian Wu #include "llvm/Support/Debug.h"
143626516bSHaojian Wu #include <vector>
153626516bSHaojian Wu 
164775ce56SHaojian Wu #define DEBUG_TYPE "clang-move"
174775ce56SHaojian Wu 
183626516bSHaojian Wu namespace clang {
193626516bSHaojian Wu namespace move {
203626516bSHaojian Wu 
213626516bSHaojian Wu void HelperDeclRefGraph::print(raw_ostream &OS) const {
223626516bSHaojian Wu   OS << " --- Call graph Dump --- \n";
233626516bSHaojian Wu   for (auto I = DeclMap.begin(); I != DeclMap.end(); ++I) {
243626516bSHaojian Wu     const CallGraphNode *N = (I->second).get();
253626516bSHaojian Wu 
263626516bSHaojian Wu     OS << "  Declarations: ";
273626516bSHaojian Wu     N->print(OS);
283626516bSHaojian Wu     OS << " (" << N << ") ";
293626516bSHaojian Wu     OS << " calls: ";
303626516bSHaojian Wu     for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {
313626516bSHaojian Wu       (*CI)->print(OS);
323626516bSHaojian Wu       OS << " (" << CI << ") ";
333626516bSHaojian Wu     }
343626516bSHaojian Wu     OS << '\n';
353626516bSHaojian Wu   }
363626516bSHaojian Wu   OS.flush();
373626516bSHaojian Wu }
383626516bSHaojian Wu 
393626516bSHaojian Wu void HelperDeclRefGraph::addEdge(const Decl *Caller, const Decl *Callee) {
403626516bSHaojian Wu   assert(Caller);
413626516bSHaojian Wu   assert(Callee);
423626516bSHaojian Wu 
433626516bSHaojian Wu   // Ignore the case where Caller equals Callee. This happens in the static
443626516bSHaojian Wu   // class member definitions in global namespace like "int CLASS::static_var =
453626516bSHaojian Wu   // 1;", its DC is a VarDel whose outmost enclosing declaration is the "CLASS"
463626516bSHaojian Wu   // CXXRecordDecl.
473626516bSHaojian Wu   if (Caller == Callee) return;
483626516bSHaojian Wu 
493626516bSHaojian Wu   // Allocate a new node, mark it as root, and process it's calls.
503626516bSHaojian Wu   CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));
513626516bSHaojian Wu   CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));
523626516bSHaojian Wu   CallerNode->addCallee(CalleeNode);
533626516bSHaojian Wu }
543626516bSHaojian Wu 
553626516bSHaojian Wu void HelperDeclRefGraph::dump() const { print(llvm::errs()); }
563626516bSHaojian Wu 
573626516bSHaojian Wu CallGraphNode *HelperDeclRefGraph::getOrInsertNode(Decl *F) {
583626516bSHaojian Wu   F = F->getCanonicalDecl();
593626516bSHaojian Wu   std::unique_ptr<CallGraphNode> &Node = DeclMap[F];
603626516bSHaojian Wu   if (Node)
613626516bSHaojian Wu     return Node.get();
623626516bSHaojian Wu 
633626516bSHaojian Wu   Node = llvm::make_unique<CallGraphNode>(F);
643626516bSHaojian Wu   return Node.get();
653626516bSHaojian Wu }
663626516bSHaojian Wu 
673626516bSHaojian Wu CallGraphNode *HelperDeclRefGraph::getNode(const Decl *D) const {
683626516bSHaojian Wu   auto I = DeclMap.find(D->getCanonicalDecl());
693626516bSHaojian Wu   return I == DeclMap.end() ? nullptr : I->second.get();
703626516bSHaojian Wu }
713626516bSHaojian Wu 
723626516bSHaojian Wu llvm::DenseSet<const CallGraphNode *>
733626516bSHaojian Wu HelperDeclRefGraph::getReachableNodes(const Decl *Root) const {
743626516bSHaojian Wu   const auto *RootNode = getNode(Root);
753626516bSHaojian Wu   if (!RootNode)
763626516bSHaojian Wu     return {};
773626516bSHaojian Wu   llvm::DenseSet<const CallGraphNode *> ConnectedNodes;
783626516bSHaojian Wu   std::function<void(const CallGraphNode *)> VisitNode =
793626516bSHaojian Wu       [&](const CallGraphNode *Node) {
803626516bSHaojian Wu         if (ConnectedNodes.count(Node))
813626516bSHaojian Wu           return;
823626516bSHaojian Wu         ConnectedNodes.insert(Node);
833626516bSHaojian Wu         for (auto It = Node->begin(), End = Node->end(); It != End; ++It)
843626516bSHaojian Wu           VisitNode(*It);
853626516bSHaojian Wu       };
863626516bSHaojian Wu 
873626516bSHaojian Wu   VisitNode(RootNode);
883626516bSHaojian Wu   return ConnectedNodes;
893626516bSHaojian Wu }
903626516bSHaojian Wu 
913626516bSHaojian Wu const Decl *HelperDeclRGBuilder::getOutmostClassOrFunDecl(const Decl *D) {
923626516bSHaojian Wu   const auto *DC = D->getDeclContext();
933626516bSHaojian Wu   const auto *Result = D;
943626516bSHaojian Wu   while (DC) {
953626516bSHaojian Wu     if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
963626516bSHaojian Wu       Result = RD;
973626516bSHaojian Wu     else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
983626516bSHaojian Wu       Result = FD;
993626516bSHaojian Wu     DC = DC->getParent();
1003626516bSHaojian Wu   }
1013626516bSHaojian Wu   return Result;
1023626516bSHaojian Wu }
1033626516bSHaojian Wu 
1043626516bSHaojian Wu void HelperDeclRGBuilder::run(
1053626516bSHaojian Wu     const ast_matchers::MatchFinder::MatchResult &Result) {
1063626516bSHaojian Wu   // Construct the graph by adding a directed edge from caller to callee.
1073626516bSHaojian Wu   //
1083626516bSHaojian Wu   // "dc" is the closest ancestor declaration of "func_ref" or "used_class", it
1093626516bSHaojian Wu   // might be not the targetted Caller Decl, we always use the outmost enclosing
1103626516bSHaojian Wu   // FunctionDecl/CXXRecordDecl of "dc". For example,
1113626516bSHaojian Wu   //
1123626516bSHaojian Wu   //   int MoveClass::F() { int a = helper(); return a; }
1133626516bSHaojian Wu   //
1143626516bSHaojian Wu   // The matched "dc" of "helper" DeclRefExpr is a VarDecl, we traverse up AST
1153626516bSHaojian Wu   // to find the outmost "MoveClass" CXXRecordDecl and use it as Caller.
1163626516bSHaojian Wu   if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
1173626516bSHaojian Wu     const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
1183626516bSHaojian Wu     assert(DC);
119*0efd5248SNicola Zaghen     LLVM_DEBUG(llvm::dbgs() << "Find helper function usage: "
1204775ce56SHaojian Wu                             << FuncRef->getDecl()->getNameAsString() << " ("
1214775ce56SHaojian Wu                             << FuncRef->getDecl() << ")\n");
1224775ce56SHaojian Wu     RG->addEdge(
1234775ce56SHaojian Wu         getOutmostClassOrFunDecl(DC->getCanonicalDecl()),
1244775ce56SHaojian Wu         getOutmostClassOrFunDecl(FuncRef->getDecl()->getCanonicalDecl()));
1253626516bSHaojian Wu   } else if (const auto *UsedClass =
1263626516bSHaojian Wu                  Result.Nodes.getNodeAs<CXXRecordDecl>("used_class")) {
1273626516bSHaojian Wu     const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
1283626516bSHaojian Wu     assert(DC);
129*0efd5248SNicola Zaghen     LLVM_DEBUG(llvm::dbgs()
130*0efd5248SNicola Zaghen                << "Find helper class usage: " << UsedClass->getNameAsString()
131*0efd5248SNicola Zaghen                << " (" << UsedClass << ")\n");
1323626516bSHaojian Wu     RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass);
1333626516bSHaojian Wu   }
1343626516bSHaojian Wu }
1353626516bSHaojian Wu 
1363626516bSHaojian Wu } // namespace move
1373626516bSHaojian Wu } // namespace clang
138