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      VersionIndependentSwift(LangOpts.SwiftVersionIndependentAPINotes) {}
 
 
   57  for (
const auto &Entry : Readers) {
 
   58    if (
auto Reader = dyn_cast_if_present<APINotesReader *>(Entry.second))
 
   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;
 
   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()))
 
   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;
 
  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);
 
  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,
 
  127                                   FileEntryRef APINotesFile) {
 
  128  assert(!Readers.contains(HeaderDir));
 
  129  if (
auto Reader = loadAPINotes(APINotesFile)) {
 
  130    Readers[HeaderDir] = Reader.release();
 
  134  Readers[HeaderDir] = 
nullptr;
 
  139APINotesManager::findAPINotesFile(DirectoryEntryRef Directory,
 
  140                                  StringRef Basename, 
bool WantPublic) {
 
  141  FileManager &FM = SM.getFileManager();
 
  143  llvm::SmallString<128> Path(Directory.
getName());
 
  145  StringRef Suffix = WantPublic ? 
"" : 
"_private";
 
  148  llvm::sys::path::append(Path, llvm::Twine(Basename) + Suffix + 
"." +
 
  154    llvm::StringRef FrameworkPath, llvm::StringRef FrameworkName, 
bool Public) {
 
  155  FileManager &FM = SM.getFileManager();
 
  157  llvm::SmallString<128> Path(FrameworkPath);
 
  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;
 
 
  219llvm::SmallVector<FileEntryRef, 2>
 
  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)
 
  352  FileID ID = SM.getFileID(ExpansionLoc);
 
  369    auto Known = Readers.find(*Dir);
 
  372    if (Known != Readers.end()) {
 
  373      ++NumDirectoryCacheHits;
 
  377        DirsVisited.insert(*Dir);
 
  383      if (
auto Reader = dyn_cast_if_present<APINotesReader *>(Known->second))
 
  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;
 
  432      if (
auto APINotesFile = 
FileMgr.getOptionalFileRef(APINotesPath)) {
 
  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
 
  453                             : 
FileMgr.getOptionalDirectoryRef(ParentPath);
 
  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.
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)
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 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)