18#include "llvm/ADT/APInt.h"
19#include "llvm/ADT/Hashing.h"
20#include "llvm/ADT/SetVector.h"
21#include "llvm/ADT/SmallPtrSet.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/Statistic.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/Support/Path.h"
26#include "llvm/Support/PrettyStackTrace.h"
29using namespace api_notes;
31#define DEBUG_TYPE "API Notes"
32STATISTIC(NumHeaderAPINotes,
"non-framework API notes files loaded");
33STATISTIC(NumPublicFrameworkAPINotes,
"framework public API notes loaded");
34STATISTIC(NumPrivateFrameworkAPINotes,
"framework private API notes loaded");
35STATISTIC(NumFrameworksSearched,
"frameworks searched");
36STATISTIC(NumDirectoriesSearched,
"header directories searched");
37STATISTIC(NumDirectoryCacheHits,
"directory cache hits");
42class PrettyStackTraceDoubleString :
public llvm::PrettyStackTraceEntry {
43 StringRef
First, Second;
46 PrettyStackTraceDoubleString(StringRef First, StringRef Second)
48 void print(raw_ostream &OS)
const override { OS <<
First << Second; }
53 :
SM(
SM), ImplicitAPINotes(LangOpts.APINotes) {}
57 for (
const auto &Entry : Readers) {
62 delete CurrentModuleReaders[ReaderKind::Public];
63 delete CurrentModuleReaders[ReaderKind::Private];
66std::unique_ptr<APINotesReader>
67APINotesManager::loadAPINotes(
FileEntryRef APINotesFile) {
68 PrettyStackTraceDoubleString Trace(
"Loading API notes from ",
83 std::unique_ptr<llvm::MemoryBuffer> CompiledBuffer;
87 diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile);
88 llvm::raw_svector_ostream OS(APINotesBuffer);
91 SMAdapter.getDiagHandler(), SMAdapter.getDiagContext()))
95 CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
96 StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
101 assert(Reader &&
"Could not load the API notes we just generated?");
105std::unique_ptr<APINotesReader>
106APINotesManager::loadAPINotes(StringRef Buffer) {
108 std::unique_ptr<llvm::MemoryBuffer> CompiledBuffer;
111 diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt);
112 llvm::raw_svector_ostream OS(APINotesBuffer);
115 SMAdapter.getDiagHandler(),
116 SMAdapter.getDiagContext()))
119 CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
120 StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
122 assert(Reader &&
"Could not load the API notes we just generated?");
126bool APINotesManager::loadAPINotes(
const DirectoryEntry *HeaderDir,
128 assert(!Readers.contains(HeaderDir));
129 if (
auto Reader = loadAPINotes(APINotesFile)) {
130 Readers[HeaderDir] = Reader.release();
134 Readers[HeaderDir] =
nullptr;
140 StringRef Basename,
bool WantPublic) {
145 StringRef Suffix = WantPublic ?
"" :
"_private";
148 llvm::sys::path::append(Path, llvm::Twine(Basename) + Suffix +
"." +
154 llvm::StringRef FrameworkPath, llvm::StringRef FrameworkName,
bool Public) {
158 unsigned FrameworkNameLength = Path.size();
160 StringRef Suffix =
Public ?
"" :
"_private";
163 llvm::sys::path::append(Path,
"APINotes");
164 llvm::sys::path::append(Path, (llvm::Twine(FrameworkName) + Suffix +
"." +
173 Path.resize(FrameworkNameLength);
174 llvm::sys::path::append(Path, Public ?
"Headers" :
"PrivateHeaders");
182 if (loadAPINotes(*HeaderDir, *APINotesFile))
187 ++NumPublicFrameworkAPINotes;
189 ++NumPrivateFrameworkAPINotes;
195 if (
File->tryGetRealPathName().empty())
198 StringRef RealFileName =
199 llvm::sys::path::filename(
File->tryGetRealPathName());
200 StringRef RealStem = llvm::sys::path::stem(RealFileName);
201 if (RealStem.ends_with(
"_private"))
204 unsigned DiagID = diag::warn_apinotes_private_case;
206 DiagID = diag::warn_apinotes_private_case_system;
215 return Submodule->ModuleMapIsPrivate;
231 if (
auto File = findAPINotesFile(Dir, ModuleName, WantPublic)) {
235 APINotes.push_back(*
File);
238 if (!ExportedModuleName.empty())
239 if (
auto File = findAPINotesFile(Dir, ExportedModuleName, WantPublic))
240 APINotes.push_back(*
File);
256 unsigned PathLen = Path.size();
258 llvm::sys::path::append(Path,
"Headers");
260 tryAPINotes(*APINotesDir,
true);
262 Path.resize(PathLen);
266 llvm::sys::path::append(Path,
"PrivateHeaders");
268 tryAPINotes(*PrivateAPINotesDir,
283 if (!APINotes.empty())
289 for (
const auto &SearchPath : SearchPaths) {
291 if (
auto File = findAPINotesFile(*SearchDir, ModuleName)) {
292 APINotes.push_back(*
File);
304 assert(!CurrentModuleReaders[ReaderKind::Public] &&
305 "Already loaded API notes for the current module?");
308 unsigned NumReaders = 0;
309 for (
auto File : APINotes) {
310 CurrentModuleReaders[NumReaders++] = loadAPINotes(
File).release();
315 return NumReaders > 0;
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?");
325 CurrentModuleReaders[NumReader++] = Reader.release();
342 if (!ImplicitAPINotes)
369 auto Known = Readers.find(*Dir);
372 if (Known != Readers.end()) {
373 ++NumDirectoryCacheHits;
377 DirsVisited.insert(*Dir);
384 Results.push_back(Reader);
389 StringRef Path = Dir->
getName();
390 if (llvm::sys::path::extension(Path) ==
".framework") {
393 auto FrameworkName = llvm::sys::path::stem(Path);
394 ++NumFrameworksSearched;
398 loadFrameworkAPINotes(Path, FrameworkName,
true);
400 loadFrameworkAPINotes(Path, FrameworkName,
false);
402 if (PublicDir || PrivateDir) {
404 Readers[*Dir] =
nullptr;
409 if (!DirsVisited.empty()) {
410 if (PublicDir && DirsVisited.back() == *PublicDir) {
411 DirsVisited.pop_back();
413 }
else if (PrivateDir && DirsVisited.back() == *PrivateDir) {
414 DirsVisited.pop_back();
420 if (
auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
421 Results.push_back(Reader);
427 llvm::sys::path::append(
431 ++NumDirectoriesSearched;
433 if (!loadAPINotes(*Dir, *APINotesFile)) {
435 if (
auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
436 Results.push_back(Reader);
443 if (!DirsVisited.insert(*Dir)) {
448 StringRef ParentPath = llvm::sys::path::parent_path(Path);
449 while (llvm::sys::path::stem(ParentPath) ==
"..")
450 ParentPath = llvm::sys::path::parent_path(ParentPath);
452 Dir = ParentPath.empty() ? std::nullopt
459 for (
const auto Visited : DirsVisited)
460 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.
llvm::DenseSet< const void * > Visited
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType)
Defines the clang::LangOptions interface.
Defines the SourceManager interface.
Defines version macros and version-related utility functions for Clang.
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.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
DiagnosticsEngine & getDiagnostics() const
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
FileManager & getFileManager() const
FileID getOrCreateFileID(FileEntryRef SourceFile, SrcMgr::CharacteristicKind FileCharacter)
Get the FileID for SourceFile if it exists.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
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.
A class that reads API notes data from a binary file that was written by the APINotesWriter.
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.
@ Public
Represents declarations accessible to all clients.
The JSON file list parser is used to communicate input to InstallAPI.