Path: blob/main/contrib/llvm-project/clang/lib/Analysis/CallGraph.cpp
35233 views
//===- CallGraph.cpp - AST-based Call graph -------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the AST-based CallGraph.9//10//===----------------------------------------------------------------------===//1112#include "clang/Analysis/CallGraph.h"13#include "clang/AST/Decl.h"14#include "clang/AST/DeclBase.h"15#include "clang/AST/DeclObjC.h"16#include "clang/AST/Expr.h"17#include "clang/AST/ExprObjC.h"18#include "clang/AST/Stmt.h"19#include "clang/AST/StmtVisitor.h"20#include "clang/Basic/IdentifierTable.h"21#include "clang/Basic/LLVM.h"22#include "llvm/ADT/PostOrderIterator.h"23#include "llvm/ADT/STLExtras.h"24#include "llvm/ADT/Statistic.h"25#include "llvm/Support/Casting.h"26#include "llvm/Support/Compiler.h"27#include "llvm/Support/DOTGraphTraits.h"28#include "llvm/Support/GraphWriter.h"29#include "llvm/Support/raw_ostream.h"30#include <cassert>31#include <memory>32#include <string>3334using namespace clang;3536#define DEBUG_TYPE "CallGraph"3738STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");39STATISTIC(NumBlockCallEdges, "Number of block call edges");4041namespace {4243/// A helper class, which walks the AST and locates all the call sites in the44/// given function body.45class CGBuilder : public StmtVisitor<CGBuilder> {46CallGraph *G;47CallGraphNode *CallerNode;4849public:50CGBuilder(CallGraph *g, CallGraphNode *N) : G(g), CallerNode(N) {}5152void VisitStmt(Stmt *S) { VisitChildren(S); }5354Decl *getDeclFromCall(CallExpr *CE) {55if (FunctionDecl *CalleeDecl = CE->getDirectCallee())56return CalleeDecl;5758// Simple detection of a call through a block.59Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();60if (BlockExpr *Block = dyn_cast<BlockExpr>(CEE)) {61NumBlockCallEdges++;62return Block->getBlockDecl();63}6465return nullptr;66}6768void addCalledDecl(Decl *D, Expr *CallExpr) {69if (G->includeCalleeInGraph(D)) {70CallGraphNode *CalleeNode = G->getOrInsertNode(D);71CallerNode->addCallee({CalleeNode, CallExpr});72}73}7475void VisitCallExpr(CallExpr *CE) {76if (Decl *D = getDeclFromCall(CE))77addCalledDecl(D, CE);78VisitChildren(CE);79}8081void VisitLambdaExpr(LambdaExpr *LE) {82if (FunctionTemplateDecl *FTD = LE->getDependentCallOperator())83for (FunctionDecl *FD : FTD->specializations())84G->VisitFunctionDecl(FD);85else if (CXXMethodDecl *MD = LE->getCallOperator())86G->VisitFunctionDecl(MD);87}8889void VisitCXXNewExpr(CXXNewExpr *E) {90if (FunctionDecl *FD = E->getOperatorNew())91addCalledDecl(FD, E);92VisitChildren(E);93}9495void VisitCXXConstructExpr(CXXConstructExpr *E) {96CXXConstructorDecl *Ctor = E->getConstructor();97if (FunctionDecl *Def = Ctor->getDefinition())98addCalledDecl(Def, E);99VisitChildren(E);100}101102// Include the evaluation of the default argument.103void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {104Visit(E->getExpr());105}106107// Include the evaluation of the default initializers in a class.108void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {109Visit(E->getExpr());110}111112// Adds may-call edges for the ObjC message sends.113void VisitObjCMessageExpr(ObjCMessageExpr *ME) {114if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {115Selector Sel = ME->getSelector();116117// Find the callee definition within the same translation unit.118Decl *D = nullptr;119if (ME->isInstanceMessage())120D = IDecl->lookupPrivateMethod(Sel);121else122D = IDecl->lookupPrivateClassMethod(Sel);123if (D) {124addCalledDecl(D, ME);125NumObjCCallEdges++;126}127}128}129130void VisitChildren(Stmt *S) {131for (Stmt *SubStmt : S->children())132if (SubStmt)133this->Visit(SubStmt);134}135};136137} // namespace138139void CallGraph::addNodesForBlocks(DeclContext *D) {140if (BlockDecl *BD = dyn_cast<BlockDecl>(D))141addNodeForDecl(BD, true);142143for (auto *I : D->decls())144if (auto *DC = dyn_cast<DeclContext>(I))145addNodesForBlocks(DC);146}147148CallGraph::CallGraph() {149Root = getOrInsertNode(nullptr);150}151152CallGraph::~CallGraph() = default;153154bool CallGraph::includeInGraph(const Decl *D) {155assert(D);156if (!D->hasBody())157return false;158159return includeCalleeInGraph(D);160}161162bool CallGraph::includeCalleeInGraph(const Decl *D) {163if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {164// We skip function template definitions, as their semantics is165// only determined when they are instantiated.166if (FD->isDependentContext())167return false;168169IdentifierInfo *II = FD->getIdentifier();170if (II && II->getName().starts_with("__inline"))171return false;172}173174return true;175}176177void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {178assert(D);179180// Allocate a new node, mark it as root, and process its calls.181CallGraphNode *Node = getOrInsertNode(D);182183// Process all the calls by this function as well.184CGBuilder builder(this, Node);185if (Stmt *Body = D->getBody())186builder.Visit(Body);187188// Include C++ constructor member initializers.189if (auto constructor = dyn_cast<CXXConstructorDecl>(D)) {190for (CXXCtorInitializer *init : constructor->inits()) {191builder.Visit(init->getInit());192}193}194}195196CallGraphNode *CallGraph::getNode(const Decl *F) const {197FunctionMapTy::const_iterator I = FunctionMap.find(F);198if (I == FunctionMap.end()) return nullptr;199return I->second.get();200}201202CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {203if (F && !isa<ObjCMethodDecl>(F))204F = F->getCanonicalDecl();205206std::unique_ptr<CallGraphNode> &Node = FunctionMap[F];207if (Node)208return Node.get();209210Node = std::make_unique<CallGraphNode>(F);211// Make Root node a parent of all functions to make sure all are reachable.212if (F)213Root->addCallee({Node.get(), /*Call=*/nullptr});214return Node.get();215}216217void CallGraph::print(raw_ostream &OS) const {218OS << " --- Call graph Dump --- \n";219220// We are going to print the graph in reverse post order, partially, to make221// sure the output is deterministic.222llvm::ReversePostOrderTraversal<const CallGraph *> RPOT(this);223for (llvm::ReversePostOrderTraversal<const CallGraph *>::rpo_iterator224I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {225const CallGraphNode *N = *I;226227OS << " Function: ";228if (N == Root)229OS << "< root >";230else231N->print(OS);232233OS << " calls: ";234for (CallGraphNode::const_iterator CI = N->begin(),235CE = N->end(); CI != CE; ++CI) {236assert(CI->Callee != Root && "No one can call the root node.");237CI->Callee->print(OS);238OS << " ";239}240OS << '\n';241}242OS.flush();243}244245LLVM_DUMP_METHOD void CallGraph::dump() const {246print(llvm::errs());247}248249void CallGraph::viewGraph() const {250llvm::ViewGraph(this, "CallGraph");251}252253void CallGraphNode::print(raw_ostream &os) const {254if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))255return ND->printQualifiedName(os);256os << "< >";257}258259LLVM_DUMP_METHOD void CallGraphNode::dump() const {260print(llvm::errs());261}262263namespace llvm {264265template <>266struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {267DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}268269static std::string getNodeLabel(const CallGraphNode *Node,270const CallGraph *CG) {271if (CG->getRoot() == Node) {272return "< root >";273}274if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))275return ND->getNameAsString();276else277return "< >";278}279};280281} // namespace llvm282283284