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/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphSummary.h"
17#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
18#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h"
19#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
20#include "llvm/ADT/STLExtras.h"
21#include <memory>
22
23using namespace clang;
24using namespace ssaf;
25
26namespace {
27class CallGraphExtractor final : public TUSummaryExtractor {
28public:
29 using TUSummaryExtractor::TUSummaryExtractor;
30
31private:
32 void HandleTranslationUnit(ASTContext &Ctx) override;
33
34 void handleCallGraphNode(const ASTContext &Ctx, const CallGraphNode *N);
35};
36} // namespace
37
38void CallGraphExtractor::HandleTranslationUnit(ASTContext &Ctx) {
39 CallGraph CG;
40 CG.addToCallGraph(
41 D: const_cast<TranslationUnitDecl *>(Ctx.getTranslationUnitDecl()));
42
43 for (const auto &N : llvm::make_second_range(c&: CG)) {
44 if (N && N->getDecl() && N->getDefinition())
45 handleCallGraphNode(Ctx, N: N.get());
46 }
47}
48
49void CallGraphExtractor::handleCallGraphNode(const ASTContext &Ctx,
50 const CallGraphNode *N) {
51 const FunctionDecl *Definition = N->getDefinition();
52
53 // FIXME: `clang::CallGraph` does not create entries for primary templates.
54 assert(!Definition->isTemplated());
55
56 auto CallerName = getEntityName(D: Definition);
57 if (!CallerName)
58 return;
59
60 auto FnSummary = std::make_unique<CallGraphSummary>();
61
62 PresumedLoc Loc =
63 Ctx.getSourceManager().getPresumedLoc(Loc: Definition->getLocation());
64 FnSummary->Definition.File = Loc.getFilename();
65 FnSummary->Definition.Line = Loc.getLine();
66 FnSummary->Definition.Column = Loc.getColumn();
67 FnSummary->PrettyName = AnalysisDeclContext::getFunctionName(D: Definition);
68
69 for (const auto &Record : N->callees()) {
70 const Decl *CalleeDecl = Record.Callee->getDecl();
71
72 // FIXME: `clang::CallGraph` does not consider indirect calls, thus this is
73 // never null.
74 assert(CalleeDecl);
75
76 // FIXME: `clang::CallGraph` does not consider ObjCMessageExprs as calls.
77 // Consequently, they don't appear as a Callee.
78 assert(!isa<ObjCMethodDecl>(CalleeDecl));
79
80 // FIXME: `clang::CallGraph` does not create entries for primary templates.
81 assert(!CalleeDecl->isTemplated());
82
83 auto CalleeName = getEntityName(D: CalleeDecl);
84 if (!CalleeName)
85 continue;
86
87 EntityId CalleeId = SummaryBuilder.addEntity(E: *CalleeName);
88 if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Val: CalleeDecl);
89 MD && MD->isVirtual()) {
90 FnSummary->VirtualCallees.insert(x: CalleeId);
91 continue;
92 }
93 FnSummary->DirectCallees.insert(x: CalleeId);
94 }
95
96 EntityId CallerId = SummaryBuilder.addEntity(E: *CallerName);
97 SummaryBuilder.addSummary(Entity: CallerId, Data: std::move(FnSummary));
98}
99
100static TUSummaryExtractorRegistry::Add<CallGraphExtractor>
101 RegisterExtractor(CallGraphSummary::Name,
102 "Extracts static call-graph information");
103
104// This anchor is used to force the linker to link in the generated object file
105// and thus register the CallGraphExtractor.
106// NOLINTNEXTLINE(misc-use-internal-linkage)
107volatile int CallGraphExtractorAnchorSource = 0;
108