1//===- CallGraphExtractor.cpp - Call Graph Summary Extractor --------------===//
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 "clang/AST/ASTContext.h"
10#include "clang/AST/Decl.h"
11#include "clang/AST/DeclCXX.h"
12#include "clang/AST/DeclObjC.h"
13#include "clang/Analysis/AnalysisDeclContext.h"
14#include "clang/Analysis/CallGraph.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/ScalableStaticAnalysis/Analyses/CallGraph/CallGraphSummary.h"
17#include "clang/ScalableStaticAnalysis/Core/TUSummary/ExtractorRegistry.h"
18#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryBuilder.h"
19#include "llvm/ADT/STLExtras.h"
20#include <memory>
21
22using namespace clang;
23using namespace ssaf;
24
25namespace {
26class CallGraphExtractor final : public TUSummaryExtractor {
27public:
28 using TUSummaryExtractor::TUSummaryExtractor;
29
30private:
31 void HandleTranslationUnit(ASTContext &Ctx) override;
32
33 void handleCallGraphNode(const ASTContext &Ctx, const CallGraphNode *N);
34};
35} // namespace
36
37void CallGraphExtractor::HandleTranslationUnit(ASTContext &Ctx) {
38 CallGraph CG;
39 CG.addToCallGraph(
40 D: const_cast<TranslationUnitDecl *>(Ctx.getTranslationUnitDecl()));
41
42 for (const auto &N : llvm::make_second_range(c&: CG)) {
43 if (N && N->getDecl() && N->getDefinition())
44 handleCallGraphNode(Ctx, N: N.get());
45 }
46}
47
48void CallGraphExtractor::handleCallGraphNode(const ASTContext &Ctx,
49 const CallGraphNode *N) {
50 const FunctionDecl *Definition = N->getDefinition();
51
52 // FIXME: `clang::CallGraph` does not create entries for primary templates.
53 assert(!Definition->isTemplated());
54
55 auto CallerId = addEntity(D: Definition);
56 if (!CallerId)
57 return;
58
59 auto FnSummary = std::make_unique<CallGraphSummary>();
60
61 PresumedLoc Loc =
62 Ctx.getSourceManager().getPresumedLoc(Loc: Definition->getLocation());
63 FnSummary->Definition.File = Loc.getFilename();
64 FnSummary->Definition.Line = Loc.getLine();
65 FnSummary->Definition.Column = Loc.getColumn();
66 FnSummary->PrettyName = AnalysisDeclContext::getFunctionName(D: Definition);
67
68 for (const auto &Record : N->callees()) {
69 const Decl *CalleeDecl = Record.Callee->getDecl();
70
71 // FIXME: `clang::CallGraph` does not consider indirect calls, thus this is
72 // never null.
73 assert(CalleeDecl);
74
75 // `clang::CallGraph` resolves ObjCMessageExprs (including property
76 // dot-syntax) to their ObjCMethodDecls and adds them as callees — see
77 // `CGBuilder::VisitObjCMessageExpr` in clang/lib/Analysis/CallGraph.cpp.
78 // ObjC dispatch is dynamic, so recording these as direct callees would be
79 // misleading; skip them until we model ObjC properly.
80 if (isa<ObjCMethodDecl>(Val: CalleeDecl))
81 continue;
82
83 // FIXME: `clang::CallGraph` does not create entries for primary templates.
84 assert(!CalleeDecl->isTemplated());
85
86 auto CalleeId = addEntity(D: cast<NamedDecl>(Val: CalleeDecl));
87 if (!CalleeId)
88 continue;
89
90 if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Val: CalleeDecl);
91 MD && MD->isVirtual()) {
92 FnSummary->VirtualCallees.insert(x: *CalleeId);
93 continue;
94 }
95 FnSummary->DirectCallees.insert(x: *CalleeId);
96 }
97
98 SummaryBuilder.addSummary(Entity: *CallerId, Data: std::move(FnSummary));
99}
100
101static TUSummaryExtractorRegistry::Add<CallGraphExtractor>
102 RegisterExtractor(CallGraphSummary::Name,
103 "Extracts static call-graph information");
104
105namespace clang::ssaf {
106// NOLINTNEXTLINE(misc-use-internal-linkage)
107volatile int CallGraphExtractorAnchorSource = 0;
108} // namespace clang::ssaf
109