clang 24.0.0git
EntitySourceLocationExtractor.cpp
Go to the documentation of this file.
1//===- EntitySourceLocationExtractor.cpp ----------------------------------===//
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
10#include "clang/AST/Decl.h"
11#include "clang/AST/DeclCXX.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/FileSystem.h"
23#include "llvm/Support/IOSandbox.h"
24#include "llvm/Support/Path.h"
25
26#include <map>
27#include <memory>
28#include <optional>
29#include <utility>
30#include <vector>
31
32namespace clang::ssaf {
34buildEntitySourceLocationsSummary(std::vector<SourceLocationRecord> Locs);
35} // namespace clang::ssaf
36
37namespace {
38using namespace clang;
39using namespace ssaf;
40
41/// Per-EntityId aggregation buffer used during one TU walk. Each visited
42/// declaration contributes one record; the buffer is committed once per
43/// EntityId at the end of the walk.
44using LocationMap = std::map<EntityId, std::vector<SourceLocationRecord>>;
45
46/// Compute a SourceLocationRecord from \p Loc. Returns std::nullopt for
47/// invalid / system-header / unreachable-on-disk paths; these are silently
48/// dropped per the spec.
49std::optional<SourceLocationRecord> makeRecord(SourceLocation Loc,
50 const SourceManager &SM) {
51 if (!Loc.isValid() || SM.isInSystemHeader(Loc))
52 return std::nullopt;
53
54 PresumedLoc PLoc = SM.getPresumedLoc(Loc);
55 if (PLoc.isInvalid())
56 return std::nullopt;
57
58 llvm::StringRef Filename(PLoc.getFilename());
59 if (Filename.empty())
60 return std::nullopt;
61
62 // Path canonicalization touches the filesystem, which is denied under the
63 // sandboxed compile drivers (e.g. xcodebuild). Reading source files the
64 // compiler is already reading is benign, so disable the sandbox for the
65 // duration of these calls.
66 llvm::SmallString<256> Abs(Filename);
68 {
69 auto SandboxOff = llvm::sys::sandbox::scopedDisable();
70 if (!llvm::sys::path::is_absolute(Abs))
71 if (auto EC = llvm::sys::fs::make_absolute(Abs))
72 return std::nullopt;
73 if (auto EC = llvm::sys::fs::real_path(Abs, Real))
74 return std::nullopt;
75 }
76
78 R.FilePath = Real.str().str();
79 R.Line = PLoc.getLine();
80 R.Column = PLoc.getColumn();
81 return R;
82}
83
84void handleNamedDecl(TUSummaryExtractor &Extractor, const NamedDecl *D,
86 LocationMap &Records) {
87 auto Rec = makeRecord(Loc, SM);
88 if (!Rec)
89 return;
90 std::optional<EntityId> Id = Extractor.addEntity(D);
91 if (!Id)
92 return;
93 Records[*Id].push_back(std::move(*Rec));
94}
95
96void handleFunction(TUSummaryExtractor &Extractor, const FunctionDecl *FD,
97 const SourceManager &SM, LocationMap &Records) {
98 handleNamedDecl(Extractor, FD, FD->getLocation(), SM, Records);
99
100 if (auto RetRec = makeRecord(FD->getReturnTypeSourceRange().getBegin(), SM))
101 if (auto RetId = Extractor.addEntityForReturn(FD))
102 Records[*RetId].push_back(std::move(*RetRec));
103
104 // The variadic '...' terminator is not represented by a ParmVarDecl in the
105 // AST, so this loop naturally skips it.
106 for (const ParmVarDecl *P : FD->parameters()) {
107 if (!P)
108 continue;
109 handleNamedDecl(Extractor, P, P->getTypeSpecStartLoc(), SM, Records);
110 }
111}
112
113/// AST visitor that records per-entity declaration source-locations as it
114/// walks. ParmVarDecls are visited as part of their parent FunctionDecl so
115/// the parameter-type-spec-start anchor is recorded once per redeclaration of
116/// the parent function.
117class EntityVisitor : public DynamicRecursiveASTVisitor {
118 TUSummaryExtractor &Extractor;
119 const SourceManager &SM;
120 LocationMap &Records;
121
122public:
123 EntityVisitor(TUSummaryExtractor &Extractor, const SourceManager &SM,
124 LocationMap &Records)
125 : Extractor(Extractor), SM(SM), Records(Records) {
126 ShouldVisitTemplateInstantiations = true;
127 ShouldVisitImplicitCode = false;
128 }
129
130 bool VisitFunctionDecl(FunctionDecl *FD) override {
131 if (FD)
132 handleFunction(Extractor, FD, SM, Records);
133 return true;
134 }
135
136 bool VisitVarDecl(VarDecl *VD) override {
137 if (VD && !isa<ParmVarDecl>(VD))
138 handleNamedDecl(Extractor, VD, VD->getLocation(), SM, Records);
139 return true;
140 }
141
142 bool VisitFieldDecl(FieldDecl *FD) override {
143 if (FD)
144 handleNamedDecl(Extractor, FD, FD->getLocation(), SM, Records);
145 return true;
146 }
147
148 bool VisitRecordDecl(RecordDecl *RD) override {
149 if (RD)
150 handleNamedDecl(Extractor, RD, RD->getLocation(), SM, Records);
151 return true;
152 }
153};
154
155class EntitySourceLocationExtractor final : public TUSummaryExtractor {
156public:
158
159private:
160 void HandleTranslationUnit(ASTContext &Ctx) override;
161};
162
163void EntitySourceLocationExtractor::HandleTranslationUnit(ASTContext &Ctx) {
164 const SourceManager &SM = Ctx.getSourceManager();
165 LocationMap Records;
166 EntityVisitor(*this, SM, Records).TraverseAST(Ctx);
167
168 for (auto &[Id, Locs] : Records) {
169 auto Summary = std::make_unique<EntitySourceLocationsSummary>(
170 buildEntitySourceLocationsSummary(std::move(Locs)));
171 [[maybe_unused]] auto [Ignored, Inserted] =
172 SummaryBuilder.addSummary(Id, std::move(Summary));
173 assert(Inserted &&
174 "EntitySourceLocations summary inserted twice for same EntityId");
175 }
176}
177
178} // namespace
179
180namespace clang::ssaf {
181// NOLINTNEXTLINE(misc-use-internal-linkage)
183} // namespace clang::ssaf
184
185static clang::ssaf::TUSummaryExtractorRegistry::Add<
186 EntitySourceLocationExtractor>
188 "Extract per-entity declaration source-locations");
Defines the clang::ASTContext interface.
static TUSummaryExtractorRegistry::Add< CallGraphExtractor > RegisterExtractor(CallGraphSummary::Name, "Extracts static call-graph information")
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::MachO::Records Records
Definition MachO.h:40
#define SM(sm)
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
SourceManager & getSourceManager()
Definition ASTContext.h:869
SourceLocation getLocation() const
Definition DeclBase.h:447
Represents a function declaration or definition.
Definition Decl.h:2029
SourceRange getReturnTypeSourceRange() const
Attempt to compute an informative source range covering the function return type.
Definition Decl.cpp:4002
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2814
This represents a decl that may have a name.
Definition Decl.h:274
Represents a parameter to a function.
Definition Decl.h:1819
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
SourceLocation getBegin() const
An EntitySourceLocationsSummary contains one SourceLocationRecord per declaration site contributed by...
std::optional< EntityId > addEntityForReturn(const FunctionDecl *FD)
Creates EntityName for the return value of FD, registers the entity, and sets its linkage atomically.
TUSummaryExtractor(TUSummaryBuilder &Builder)
std::optional< EntityId > addEntity(const NamedDecl *D)
Creates EntityName from the Decl, registers the entity, and sets its linkage atomically.
volatile int EntitySourceLocationExtractorAnchorSource
EntitySourceLocationsSummary buildEntitySourceLocationsSummary(std::vector< SourceLocationRecord > Locs)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
A canonical (file, line, column) triple for one declaration site.