clang: lib/APINotes/APINotesManager.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
18#include "llvm/ADT/APInt.h"
19#include "llvm/ADT/SetVector.h"
20#include "llvm/ADT/SmallPtrSet.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/Statistic.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/Path.h"
25#include "llvm/Support/PrettyStackTrace.h"
26
27using namespace clang;
29
30#define DEBUG_TYPE "API Notes"
31STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded");
32STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded");
33STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded");
34STATISTIC(NumFrameworksSearched, "frameworks searched");
35STATISTIC(NumDirectoriesSearched, "header directories searched");
36STATISTIC(NumDirectoryCacheHits, "directory cache hits");
37
38namespace {
39
40
41class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry {
42 StringRef First, Second;
43
44public:
45 PrettyStackTraceDoubleString(StringRef First, StringRef Second)
47 void print(raw_ostream &OS) const override { OS << First << Second; }
48};
49}
50
52 : SM(SM), ImplicitAPINotes(LangOpts.APINotes),
53 VersionIndependentSwift(LangOpts.SwiftVersionIndependentAPINotes) {}
54
56
57 for (const auto &Entry : Readers) {
58 if (auto Reader = dyn_cast_if_present<APINotesReader *>(Entry.second))
59 delete Reader;
60 }
61
62 delete CurrentModuleReaders[ReaderKind::Public];
63 delete CurrentModuleReaders[ReaderKind::Private];
64}
65
66std::unique_ptr
67APINotesManager::loadAPINotes(FileEntryRef APINotesFile) {
68 PrettyStackTraceDoubleString Trace("Loading API notes from ",
70
71
72 auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User);
73 auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation());
74 if (!SourceBuffer)
75 return nullptr;
76
77
78
79
80
81
83 std::unique_ptrllvm::MemoryBuffer CompiledBuffer;
84 {
86 SM, SM.getDiagnostics(), diag::err_apinotes_message,
87 diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile);
88 llvm::raw_svector_ostream OS(APINotesBuffer);
90 SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS,
91 SMAdapter.getDiagHandler(), SMAdapter.getDiagContext()))
92 return nullptr;
93
94
95 CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
96 StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
97 }
98
99
101 assert(Reader && "Could not load the API notes we just generated?");
102 return Reader;
103}
104
105std::unique_ptr
106APINotesManager::loadAPINotes(StringRef Buffer) {
108 std::unique_ptrllvm::MemoryBuffer CompiledBuffer;
110 SM, SM.getDiagnostics(), diag::err_apinotes_message,
111 diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt);
112 llvm::raw_svector_ostream OS(APINotesBuffer);
113
115 SMAdapter.getDiagHandler(),
116 SMAdapter.getDiagContext()))
117 return nullptr;
118
119 CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
120 StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
122 assert(Reader && "Could not load the API notes we just generated?");
123 return Reader;
124}
125
126bool APINotesManager::loadAPINotes(const DirectoryEntry *HeaderDir,
127 FileEntryRef APINotesFile) {
128 assert(!Readers.contains(HeaderDir));
129 if (auto Reader = loadAPINotes(APINotesFile)) {
130 Readers[HeaderDir] = Reader.release();
131 return false;
132 }
133
134 Readers[HeaderDir] = nullptr;
135 return true;
136}
137
139APINotesManager::findAPINotesFile(DirectoryEntryRef Directory,
140 StringRef Basename, bool WantPublic) {
141 FileManager &FM = SM.getFileManager();
142
143 llvm::SmallString<128> Path(Directory.getName());
144
145 StringRef Suffix = WantPublic ? "" : "_private";
146
147
148 llvm::sys::path::append(Path, llvm::Twine(Basename) + Suffix + "." +
151}
152
154 llvm::StringRef FrameworkPath, llvm::StringRef FrameworkName, bool Public) {
155 FileManager &FM = SM.getFileManager();
156
157 llvm::SmallString<128> Path(FrameworkPath);
158 unsigned FrameworkNameLength = Path.size();
159
160 StringRef Suffix = Public ? "" : "_private";
161
162
163 llvm::sys::path::append(Path, "APINotes");
164 llvm::sys::path::append(Path, (llvm::Twine(FrameworkName) + Suffix + "." +
166
167
169 if (!APINotesFile)
170 return std::nullopt;
171
172
173 Path.resize(FrameworkNameLength);
174 llvm::sys::path::append(Path, Public ? "Headers" : "PrivateHeaders");
175
176
178 if (!HeaderDir)
179 return std::nullopt;
180
181
182 if (loadAPINotes(*HeaderDir, *APINotesFile))
183 return std::nullopt;
184
185
186 if (Public)
187 ++NumPublicFrameworkAPINotes;
188 else
189 ++NumPrivateFrameworkAPINotes;
190 return *HeaderDir;
191}
192
195 if (File->tryGetRealPathName().empty())
196 return;
197
198 StringRef RealFileName =
199 llvm::sys::path::filename(File->tryGetRealPathName());
200 StringRef RealStem = llvm::sys::path::stem(RealFileName);
201 if (RealStem.ends_with("_private"))
202 return;
203
204 unsigned DiagID = diag::warn_apinotes_private_case;
206 DiagID = diag::warn_apinotes_private_case_system;
207
209}
210
211
212
214 return llvm::any_of(M->submodules(), [](const Module *Submodule) {
215 return Submodule->ModuleMapIsPrivate;
216 });
217}
218
219llvm::SmallVector<FileEntryRef, 2>
226
227
228 if (LookInModule && M->Directory) {
229
231 if (auto File = findAPINotesFile(Dir, ModuleName, WantPublic)) {
232 if (!WantPublic)
234
235 APINotes.push_back(*File);
236 }
237
238 if (!ExportedModuleName.empty())
239 if (auto File = findAPINotesFile(Dir, ExportedModuleName, WantPublic))
240 APINotes.push_back(*File);
241 };
242
244
245
246
247
248
249
250
251
252
254
256 unsigned PathLen = Path.size();
257
258 llvm::sys::path::append(Path, "Headers");
260 tryAPINotes(*APINotesDir, true);
261
262 Path.resize(PathLen);
263 }
264
266 llvm::sys::path::append(Path, "PrivateHeaders");
268 tryAPINotes(*PrivateAPINotesDir,
270 }
271 } else {
272
273
274
275
276
277
278 tryAPINotes(*M->Directory, true);
280 tryAPINotes(*M->Directory, false);
281 }
282
283 if (!APINotes.empty())
284 return APINotes;
285 }
286
287
288
289 for (const auto &SearchPath : SearchPaths) {
291 if (auto File = findAPINotesFile(*SearchDir, ModuleName)) {
292 APINotes.push_back(*File);
293 return APINotes;
294 }
295 }
296 }
297
298
299 return APINotes;
300}
301
304 assert(!CurrentModuleReaders[ReaderKind::Public] &&
305 "Already loaded API notes for the current module?");
306
308 unsigned NumReaders = 0;
309 for (auto File : APINotes) {
310 CurrentModuleReaders[NumReaders++] = loadAPINotes(File).release();
313 }
314
315 return NumReaders > 0;
316}
317
320 unsigned NumReader = 0;
321 for (auto Buf : Buffers) {
322 auto Reader = loadAPINotes(Buf);
323 assert(Reader && "Could not load the API notes we just generated?");
324
325 CurrentModuleReaders[NumReader++] = Reader.release();
326 }
327 return NumReader;
328}
329
333
334
338 return Results;
339 }
340
341
342 if (!ImplicitAPINotes)
343 return Results;
344
345
347 return Results;
348
349
350
351 SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
352 FileID ID = SM.getFileID(ExpansionLoc);
353 if (ID.isInvalid())
354 return Results;
357 return Results;
358
359
360
366 DirsVisited;
367 do {
368
369 auto Known = Readers.find(*Dir);
370
371
372 if (Known != Readers.end()) {
373 ++NumDirectoryCacheHits;
374
375
377 DirsVisited.insert(*Dir);
379 continue;
380 }
381
382
383 if (auto Reader = dyn_cast_if_present<APINotesReader *>(Known->second))
384 Results.push_back(Reader);
385 break;
386 }
387
388
389 StringRef Path = Dir->getName();
390 if (llvm::sys::path::extension(Path) == ".framework") {
391
392
393 auto FrameworkName = llvm::sys::path::stem(Path);
394 ++NumFrameworksSearched;
395
396
398 loadFrameworkAPINotes(Path, FrameworkName, true);
400 loadFrameworkAPINotes(Path, FrameworkName, false);
401
402 if (PublicDir || PrivateDir) {
403
404 Readers[*Dir] = nullptr;
405
406
407
408
409 if (!DirsVisited.empty()) {
410 if (PublicDir && DirsVisited.back() == *PublicDir) {
411 DirsVisited.pop_back();
412 Dir = *PublicDir;
413 } else if (PrivateDir && DirsVisited.back() == *PrivateDir) {
414 DirsVisited.pop_back();
415 Dir = *PrivateDir;
416 }
417 }
418
419
420 if (auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
421 Results.push_back(Reader);
422 break;
423 }
424 } else {
425
427 llvm::sys::path::append(
429
430
431 ++NumDirectoriesSearched;
432 if (auto APINotesFile = FileMgr.getOptionalFileRef(APINotesPath)) {
433 if (!loadAPINotes(*Dir, *APINotesFile)) {
434 ++NumHeaderAPINotes;
435 if (auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
436 Results.push_back(Reader);
437 break;
438 }
439 }
440 }
441
442
443 if (!DirsVisited.insert(*Dir)) {
444 Dir = std::nullopt;
445 break;
446 }
447
448 StringRef ParentPath = llvm::sys::path::parent_path(Path);
449 while (llvm::sys::path::stem(ParentPath) == "..")
450 ParentPath = llvm::sys::path::parent_path(ParentPath);
451
452 Dir = ParentPath.empty() ? std::nullopt
453 : FileMgr.getOptionalDirectoryRef(ParentPath);
454 } while (Dir);
455
456
457
458
459 for (const auto Visited : DirsVisited)
460 Readers[Visited] = Dir ? ReaderEntry(*Dir) : ReaderEntry();
461
462 return Results;
463}
static void checkPrivateAPINotesName(DiagnosticsEngine &Diags, const FileEntry *File, const Module *M)
Definition APINotesManager.cpp:193
static bool hasPrivateSubmodules(const Module *M)
Definition APINotesManager.cpp:213
STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded")
Defines the Diagnostic-related interfaces.
Defines the clang::FileManager interface and associated types.
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
Defines the clang::LangOptions interface.
Defines the clang::Module class, which describes a module in the source code.
Defines the SourceManager interface.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
A reference to a DirectoryEntry that includes the name of the directory as it was accessed by the Fil...
StringRef getName() const
Cached information about one directory (either on disk or in the virtual file system).
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
StringRef getName() const
The name of this FileEntry.
Cached information about one file (either on disk or in the virtual file system).
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements support for file system lookup, file system caching, and directory search management.
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
OptionalDirectoryEntryRef getOptionalDirectoryRef(StringRef DirName, bool CacheFailure=true)
Get a DirectoryEntryRef if it exists, without doing anything on error.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Describes a module or submodule.
StringRef getTopLevelModuleName() const
Retrieve the name of the top-level module.
unsigned IsSystem
Whether this is a "system" module (which assumes that all headers in it are system headers).
std::string Name
The name of this module.
llvm::iterator_range< submodule_iterator > submodules()
unsigned ModuleMapIsPrivate
Whether this module came from a "private" module map, found next to a regular (public) module map.
OptionalDirectoryEntryRef Directory
The build directory of this module.
std::string APINotesFile
For the debug info, the path to this module's .apinotes file, if any.
unsigned IsFramework
Whether this is a framework module.
std::string ExportAsModule
The module through which entities defined in this module will eventually be exposed,...
Module * getTopLevelModule()
Retrieve the top-level module for this (sub)module, which may be this module.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
An adapter that can be used to translate diagnostics from one or more llvm::SourceMgr instances to a ...
APINotesManager(SourceManager &SM, const LangOptions &LangOpts)
Definition APINotesManager.cpp:51
llvm::SmallVector< FileEntryRef, 2 > getCurrentModuleAPINotes(Module *M, bool LookInModule, ArrayRef< std::string > SearchPaths)
Get FileEntry for the APINotes of the module that is currently being compiled.
Definition APINotesManager.cpp:220
ArrayRef< APINotesReader * > getCurrentModuleReaders() const
Retrieve the set of API notes readers for the current module.
bool loadCurrentModuleAPINotesFromBuffer(ArrayRef< StringRef > Buffers)
Load Compiled API notes for current module.
Definition APINotesManager.cpp:318
llvm::SmallVector< APINotesReader *, 2 > findAPINotes(SourceLocation Loc)
Find the API notes readers that correspond to the given source location.
Definition APINotesManager.cpp:331
bool loadCurrentModuleAPINotes(Module *M, bool LookInModule, ArrayRef< std::string > SearchPaths)
Load the API notes for the current module.
Definition APINotesManager.cpp:302
~APINotesManager()
Definition APINotesManager.cpp:55
static std::unique_ptr< APINotesReader > Create(std::unique_ptr< llvm::MemoryBuffer > InputBuffer, llvm::VersionTuple SwiftVersion)
Create a new API notes reader from the given member buffer, which contains the contents of a binary A...
bool compileAPINotes(llvm::StringRef YAMLInput, const FileEntry *SourceFile, llvm::raw_ostream &OS, llvm::SourceMgr::DiagHandlerTy DiagHandler=nullptr, void *DiagHandlerCtxt=nullptr)
Converts API notes from YAML format to binary format.
static const constexpr char SOURCE_APINOTES_EXTENSION[]
The file extension used for the source representation of API notes.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
CustomizableOptional< DirectoryEntryRef > OptionalDirectoryEntryRef
U cast(CodeGen::Address addr)