llvm-project
136 строк · 4.6 Кб
1//===-- HelperDeclRefGraph.cpp - AST-based call graph for helper decls ----===//
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#include "HelperDeclRefGraph.h"10#include "Move.h"11#include "clang/AST/Decl.h"12#include "llvm/Support/Debug.h"13#include <vector>14
15#define DEBUG_TYPE "clang-move"16
17namespace clang {18namespace move {19
20void HelperDeclRefGraph::print(raw_ostream &OS) const {21OS << " --- Call graph Dump --- \n";22for (auto I = DeclMap.begin(); I != DeclMap.end(); ++I) {23const CallGraphNode *N = (I->second).get();24
25OS << " Declarations: ";26N->print(OS);27OS << " (" << N << ") ";28OS << " calls: ";29for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {30CI->Callee->print(OS);31OS << " (" << CI << ") ";32}33OS << '\n';34}35OS.flush();36}
37
38void HelperDeclRefGraph::addEdge(const Decl *Caller, const Decl *Callee) {39assert(Caller);40assert(Callee);41
42// Ignore the case where Caller equals Callee. This happens in the static43// class member definitions in global namespace like "int CLASS::static_var =44// 1;", its DC is a VarDel whose outmost enclosing declaration is the "CLASS"45// CXXRecordDecl.46if (Caller == Callee) return;47
48// Allocate a new node, mark it as root, and process it's calls.49CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));50CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));51CallerNode->addCallee({CalleeNode, /*CallExpr=*/nullptr});52}
53
54void HelperDeclRefGraph::dump() const { print(llvm::errs()); }55
56CallGraphNode *HelperDeclRefGraph::getOrInsertNode(Decl *F) {57F = F->getCanonicalDecl();58std::unique_ptr<CallGraphNode> &Node = DeclMap[F];59if (Node)60return Node.get();61
62Node = std::make_unique<CallGraphNode>(F);63return Node.get();64}
65
66CallGraphNode *HelperDeclRefGraph::getNode(const Decl *D) const {67auto I = DeclMap.find(D->getCanonicalDecl());68return I == DeclMap.end() ? nullptr : I->second.get();69}
70
71llvm::DenseSet<const CallGraphNode *>72HelperDeclRefGraph::getReachableNodes(const Decl *Root) const {73const auto *RootNode = getNode(Root);74if (!RootNode)75return {};76llvm::DenseSet<const CallGraphNode *> ConnectedNodes;77std::function<void(const CallGraphNode *)> VisitNode =78[&](const CallGraphNode *Node) {79if (ConnectedNodes.count(Node))80return;81ConnectedNodes.insert(Node);82for (auto It = Node->begin(), End = Node->end(); It != End; ++It)83VisitNode(*It);84};85
86VisitNode(RootNode);87return ConnectedNodes;88}
89
90const Decl *HelperDeclRGBuilder::getOutmostClassOrFunDecl(const Decl *D) {91const auto *DC = D->getDeclContext();92const auto *Result = D;93while (DC) {94if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))95Result = RD;96else if (const auto *FD = dyn_cast<FunctionDecl>(DC))97Result = FD;98DC = DC->getParent();99}100return Result;101}
102
103void HelperDeclRGBuilder::run(104const ast_matchers::MatchFinder::MatchResult &Result) {105// Construct the graph by adding a directed edge from caller to callee.106//107// "dc" is the closest ancestor declaration of "func_ref" or "used_class", it108// might be not the targetted Caller Decl, we always use the outmost enclosing109// FunctionDecl/CXXRecordDecl of "dc". For example,110//111// int MoveClass::F() { int a = helper(); return a; }112//113// The matched "dc" of "helper" DeclRefExpr is a VarDecl, we traverse up AST114// to find the outmost "MoveClass" CXXRecordDecl and use it as Caller.115if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {116const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");117assert(DC);118LLVM_DEBUG(llvm::dbgs() << "Find helper function usage: "119<< FuncRef->getDecl()->getDeclName() << " ("120<< FuncRef->getDecl() << ")\n");121RG->addEdge(122getOutmostClassOrFunDecl(DC->getCanonicalDecl()),123getOutmostClassOrFunDecl(FuncRef->getDecl()->getCanonicalDecl()));124} else if (const auto *UsedClass =125Result.Nodes.getNodeAs<CXXRecordDecl>("used_class")) {126const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");127assert(DC);128LLVM_DEBUG(llvm::dbgs()129<< "Find helper class usage: " << UsedClass->getDeclName()130<< " (" << UsedClass << ")\n");131RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass);132}133}
134
135} // namespace move136} // namespace clang137