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"
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");
41class PrettyStackTraceDoubleString :
public llvm::PrettyStackTraceEntry {
42 StringRef
First, Second;
45 PrettyStackTraceDoubleString(StringRef
First, StringRef Second)
47 void print(raw_ostream &OS)
const override {
OS << First << Second; }
52 : SM(SM), ImplicitAPINotes(LangOpts.APINotes),
53 HasAPINotes(LangOpts.APINotes),
54 VersionIndependentSwift(LangOpts.SwiftVersionIndependentAPINotes) {}
58 for (
const auto &Entry : Readers) {
59 if (
auto Reader = dyn_cast_if_present<APINotesReader *>(Entry.second))
63 delete CurrentModuleReaders[ReaderKind::Public];
64 delete CurrentModuleReaders[ReaderKind::Private];
67std::unique_ptr<APINotesReader>
68APINotesManager::loadAPINotes(
FileEntryRef APINotesFile) {
69 PrettyStackTraceDoubleString Trace(
"Loading API notes from ",
84 std::unique_ptr<llvm::MemoryBuffer> CompiledBuffer;
87 SM,
SM.getDiagnostics(), diag::err_apinotes_message,
88 diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile);
89 llvm::raw_svector_ostream OS(APINotesBuffer);
91 SourceBuffer->getBuffer(),
SM.getFileEntryForID(SourceFileID), OS,
92 SMAdapter.getDiagHandler(), SMAdapter.getDiagContext()))
96 CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
97 StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
103 llvm::consumeError(Reader.takeError());
106 return std::move(Reader.get());
109std::unique_ptr<APINotesReader>
110APINotesManager::loadAPINotes(StringRef Buffer) {
111 llvm::SmallVector<char, 1024> APINotesBuffer;
112 std::unique_ptr<llvm::MemoryBuffer> CompiledBuffer;
113 SourceMgrAdapter SMAdapter(
114 SM, SM.getDiagnostics(), diag::err_apinotes_message,
115 diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt);
116 llvm::raw_svector_ostream
OS(APINotesBuffer);
119 SMAdapter.getDiagHandler(),
120 SMAdapter.getDiagContext()))
123 CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
124 StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
128 llvm::consumeError(Reader.takeError());
131 return std::move(Reader.get());
134bool APINotesManager::loadAPINotes(
const DirectoryEntry *HeaderDir,
135 FileEntryRef APINotesFile) {
136 assert(!Readers.contains(HeaderDir));
137 if (
auto Reader = loadAPINotes(APINotesFile)) {
138 Readers[HeaderDir] = Reader.release();
142 Readers[HeaderDir] =
nullptr;
147APINotesManager::findAPINotesFile(DirectoryEntryRef Directory,
148 StringRef Basename,
bool WantPublic) {
149 FileManager &FM = SM.getFileManager();
151 llvm::SmallString<128> Path(Directory.
getName());
153 StringRef Suffix = WantPublic ?
"" :
"_private";
156 llvm::sys::path::append(Path, llvm::Twine(Basename) + Suffix +
"." +
162 llvm::StringRef FrameworkPath, llvm::StringRef FrameworkName,
bool Public) {
163 FileManager &FM = SM.getFileManager();
165 llvm::SmallString<128> Path(FrameworkPath);
166 unsigned FrameworkNameLength = Path.size();
168 StringRef Suffix = Public ?
"" :
"_private";
171 llvm::sys::path::append(Path,
"APINotes");
172 llvm::sys::path::append(Path, (llvm::Twine(FrameworkName) + Suffix +
"." +
181 Path.resize(FrameworkNameLength);
182 llvm::sys::path::append(Path, Public ?
"Headers" :
"PrivateHeaders");
190 if (loadAPINotes(*HeaderDir, *APINotesFile))
195 ++NumPublicFrameworkAPINotes;
197 ++NumPrivateFrameworkAPINotes;
203 if (
File->tryGetRealPathName().empty())
206 StringRef RealFileName =
207 llvm::sys::path::filename(
File->tryGetRealPathName());
208 StringRef RealStem = llvm::sys::path::stem(RealFileName);
209 if (RealStem.ends_with(
"_private"))
212 unsigned DiagID = diag::warn_apinotes_private_case;
214 DiagID = diag::warn_apinotes_private_case_system;
223 return Submodule->ModuleMapIsPrivate;
227llvm::SmallVector<FileEntryRef, 2>
239 if (
auto File = findAPINotesFile(Dir, ModuleName, WantPublic)) {
243 APINotes.push_back(*
File);
246 if (!ExportedModuleName.empty())
247 if (
auto File = findAPINotesFile(Dir, ExportedModuleName, WantPublic))
248 APINotes.push_back(*
File);
264 unsigned PathLen = Path.size();
266 llvm::sys::path::append(Path,
"Headers");
268 tryAPINotes(*APINotesDir,
true);
270 Path.resize(PathLen);
274 llvm::sys::path::append(Path,
"PrivateHeaders");
276 tryAPINotes(*PrivateAPINotesDir,
291 if (!APINotes.empty())
297 for (
const auto &SearchPath : SearchPaths) {
299 if (
auto File = findAPINotesFile(*SearchDir, ModuleName)) {
300 APINotes.push_back(*
File);
312 assert(!CurrentModuleReaders[ReaderKind::Public] &&
313 "Already loaded API notes for the current module?");
316 unsigned NumReaders = 0;
317 for (
auto File : APINotes) {
318 CurrentModuleReaders[NumReaders++] = loadAPINotes(
File).release();
325 return NumReaders > 0;
330 unsigned NumReader = 0;
331 for (
auto Buf : Buffers) {
332 auto Reader = loadAPINotes(Buf);
333 assert(Reader &&
"Could not load the API notes we just generated?");
335 CurrentModuleReaders[NumReader++] = Reader.release();
354 if (!ImplicitAPINotes)
364 FileID ID = SM.getFileID(ExpansionLoc);
381 auto Known = Readers.find(*Dir);
384 if (Known != Readers.end()) {
385 ++NumDirectoryCacheHits;
389 DirsVisited.insert(*Dir);
395 if (
auto Reader = dyn_cast_if_present<APINotesReader *>(Known->second))
396 Results.push_back(Reader);
401 StringRef Path = Dir->
getName();
402 if (llvm::sys::path::extension(Path) ==
".framework") {
405 auto FrameworkName = llvm::sys::path::stem(Path);
406 ++NumFrameworksSearched;
410 loadFrameworkAPINotes(Path, FrameworkName,
true);
412 loadFrameworkAPINotes(Path, FrameworkName,
false);
414 if (PublicDir || PrivateDir) {
416 Readers[*Dir] =
nullptr;
421 if (!DirsVisited.empty()) {
422 if (PublicDir && DirsVisited.back() == *PublicDir) {
423 DirsVisited.pop_back();
425 }
else if (PrivateDir && DirsVisited.back() == *PrivateDir) {
426 DirsVisited.pop_back();
432 if (
auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
433 Results.push_back(Reader);
439 llvm::sys::path::append(
443 ++NumDirectoriesSearched;
444 if (
auto APINotesFile =
FileMgr.getOptionalFileRef(APINotesPath)) {
445 if (!loadAPINotes(*Dir, *APINotesFile)) {
447 if (
auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
448 Results.push_back(Reader);
455 if (!DirsVisited.insert(*Dir)) {
460 StringRef ParentPath = llvm::sys::path::parent_path(Path);
461 while (llvm::sys::path::stem(ParentPath) ==
"..")
462 ParentPath = llvm::sys::path::parent_path(ParentPath);
464 Dir = ParentPath.empty() ? std::nullopt
465 :
FileMgr.getOptionalDirectoryRef(ParentPath);
471 for (
const auto Visited : DirsVisited)
472 Readers[Visited] = Dir ? ReaderEntry(*Dir) : ReaderEntry();
static void checkPrivateAPINotesName(DiagnosticsEngine &Diags, const FileEntry *File, const Module *M)
static bool hasPrivateSubmodules(const Module *M)
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, const Context &Ctx, 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, bool IsText=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)
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.
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.
llvm::SmallVector< APINotesReader *, 2 > findAPINotes(SourceLocation Loc)
Find the API notes readers that correspond to the given source location.
bool loadCurrentModuleAPINotes(Module *M, bool LookInModule, ArrayRef< std::string > SearchPaths)
Load the API notes for the current module.
static llvm::Expected< std::unique_ptr< APINotesReader > > Create(std::unique_ptr< llvm::MemoryBuffer > InputBuffer, llvm::VersionTuple SwiftVersion)
Create a new API notes reader from the given memory 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)