xref: /freebsd-src/contrib/llvm-project/clang/lib/APINotes/APINotesManager.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15f757f3fSDimitry Andric //===--- APINotesManager.cpp - Manage API Notes Files ---------------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #include "clang/APINotes/APINotesManager.h"
105f757f3fSDimitry Andric #include "clang/APINotes/APINotesReader.h"
115f757f3fSDimitry Andric #include "clang/APINotes/APINotesYAMLCompiler.h"
125f757f3fSDimitry Andric #include "clang/Basic/Diagnostic.h"
135f757f3fSDimitry Andric #include "clang/Basic/FileManager.h"
145f757f3fSDimitry Andric #include "clang/Basic/LangOptions.h"
15*0fca6ea1SDimitry Andric #include "clang/Basic/Module.h"
165f757f3fSDimitry Andric #include "clang/Basic/SourceManager.h"
175f757f3fSDimitry Andric #include "clang/Basic/SourceMgrAdapter.h"
185f757f3fSDimitry Andric #include "clang/Basic/Version.h"
195f757f3fSDimitry Andric #include "llvm/ADT/APInt.h"
205f757f3fSDimitry Andric #include "llvm/ADT/Hashing.h"
215f757f3fSDimitry Andric #include "llvm/ADT/SetVector.h"
225f757f3fSDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
235f757f3fSDimitry Andric #include "llvm/ADT/SmallVector.h"
245f757f3fSDimitry Andric #include "llvm/ADT/Statistic.h"
255f757f3fSDimitry Andric #include "llvm/Support/MemoryBuffer.h"
265f757f3fSDimitry Andric #include "llvm/Support/Path.h"
275f757f3fSDimitry Andric #include "llvm/Support/PrettyStackTrace.h"
285f757f3fSDimitry Andric 
295f757f3fSDimitry Andric using namespace clang;
305f757f3fSDimitry Andric using namespace api_notes;
315f757f3fSDimitry Andric 
325f757f3fSDimitry Andric #define DEBUG_TYPE "API Notes"
335f757f3fSDimitry Andric STATISTIC(NumHeaderAPINotes, "non-framework API notes files loaded");
345f757f3fSDimitry Andric STATISTIC(NumPublicFrameworkAPINotes, "framework public API notes loaded");
355f757f3fSDimitry Andric STATISTIC(NumPrivateFrameworkAPINotes, "framework private API notes loaded");
365f757f3fSDimitry Andric STATISTIC(NumFrameworksSearched, "frameworks searched");
375f757f3fSDimitry Andric STATISTIC(NumDirectoriesSearched, "header directories searched");
385f757f3fSDimitry Andric STATISTIC(NumDirectoryCacheHits, "directory cache hits");
395f757f3fSDimitry Andric 
405f757f3fSDimitry Andric namespace {
415f757f3fSDimitry Andric /// Prints two successive strings, which much be kept alive as long as the
425f757f3fSDimitry Andric /// PrettyStackTrace entry.
435f757f3fSDimitry Andric class PrettyStackTraceDoubleString : public llvm::PrettyStackTraceEntry {
445f757f3fSDimitry Andric   StringRef First, Second;
455f757f3fSDimitry Andric 
465f757f3fSDimitry Andric public:
475f757f3fSDimitry Andric   PrettyStackTraceDoubleString(StringRef First, StringRef Second)
485f757f3fSDimitry Andric       : First(First), Second(Second) {}
495f757f3fSDimitry Andric   void print(raw_ostream &OS) const override { OS << First << Second; }
505f757f3fSDimitry Andric };
515f757f3fSDimitry Andric } // namespace
525f757f3fSDimitry Andric 
535f757f3fSDimitry Andric APINotesManager::APINotesManager(SourceManager &SM, const LangOptions &LangOpts)
545f757f3fSDimitry Andric     : SM(SM), ImplicitAPINotes(LangOpts.APINotes) {}
555f757f3fSDimitry Andric 
565f757f3fSDimitry Andric APINotesManager::~APINotesManager() {
575f757f3fSDimitry Andric   // Free the API notes readers.
585f757f3fSDimitry Andric   for (const auto &Entry : Readers) {
595f757f3fSDimitry Andric     if (auto Reader = Entry.second.dyn_cast<APINotesReader *>())
605f757f3fSDimitry Andric       delete Reader;
615f757f3fSDimitry Andric   }
625f757f3fSDimitry Andric 
635f757f3fSDimitry Andric   delete CurrentModuleReaders[ReaderKind::Public];
645f757f3fSDimitry Andric   delete CurrentModuleReaders[ReaderKind::Private];
655f757f3fSDimitry Andric }
665f757f3fSDimitry Andric 
675f757f3fSDimitry Andric std::unique_ptr<APINotesReader>
685f757f3fSDimitry Andric APINotesManager::loadAPINotes(FileEntryRef APINotesFile) {
695f757f3fSDimitry Andric   PrettyStackTraceDoubleString Trace("Loading API notes from ",
705f757f3fSDimitry Andric                                      APINotesFile.getName());
715f757f3fSDimitry Andric 
725f757f3fSDimitry Andric   // Open the source file.
735f757f3fSDimitry Andric   auto SourceFileID = SM.getOrCreateFileID(APINotesFile, SrcMgr::C_User);
745f757f3fSDimitry Andric   auto SourceBuffer = SM.getBufferOrNone(SourceFileID, SourceLocation());
755f757f3fSDimitry Andric   if (!SourceBuffer)
765f757f3fSDimitry Andric     return nullptr;
775f757f3fSDimitry Andric 
785f757f3fSDimitry Andric   // Compile the API notes source into a buffer.
795f757f3fSDimitry Andric   // FIXME: Either propagate OSType through or, better yet, improve the binary
805f757f3fSDimitry Andric   // APINotes format to maintain complete availability information.
815f757f3fSDimitry Andric   // FIXME: We don't even really need to go through the binary format at all;
825f757f3fSDimitry Andric   // we're just going to immediately deserialize it again.
835f757f3fSDimitry Andric   llvm::SmallVector<char, 1024> APINotesBuffer;
845f757f3fSDimitry Andric   std::unique_ptr<llvm::MemoryBuffer> CompiledBuffer;
855f757f3fSDimitry Andric   {
865f757f3fSDimitry Andric     SourceMgrAdapter SMAdapter(
875f757f3fSDimitry Andric         SM, SM.getDiagnostics(), diag::err_apinotes_message,
885f757f3fSDimitry Andric         diag::warn_apinotes_message, diag::note_apinotes_message, APINotesFile);
895f757f3fSDimitry Andric     llvm::raw_svector_ostream OS(APINotesBuffer);
905f757f3fSDimitry Andric     if (api_notes::compileAPINotes(
915f757f3fSDimitry Andric             SourceBuffer->getBuffer(), SM.getFileEntryForID(SourceFileID), OS,
925f757f3fSDimitry Andric             SMAdapter.getDiagHandler(), SMAdapter.getDiagContext()))
935f757f3fSDimitry Andric       return nullptr;
945f757f3fSDimitry Andric 
955f757f3fSDimitry Andric     // Make a copy of the compiled form into the buffer.
965f757f3fSDimitry Andric     CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
975f757f3fSDimitry Andric         StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
985f757f3fSDimitry Andric   }
995f757f3fSDimitry Andric 
1005f757f3fSDimitry Andric   // Load the binary form we just compiled.
1015f757f3fSDimitry Andric   auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion);
1025f757f3fSDimitry Andric   assert(Reader && "Could not load the API notes we just generated?");
1035f757f3fSDimitry Andric   return Reader;
1045f757f3fSDimitry Andric }
1055f757f3fSDimitry Andric 
1065f757f3fSDimitry Andric std::unique_ptr<APINotesReader>
1075f757f3fSDimitry Andric APINotesManager::loadAPINotes(StringRef Buffer) {
1085f757f3fSDimitry Andric   llvm::SmallVector<char, 1024> APINotesBuffer;
1095f757f3fSDimitry Andric   std::unique_ptr<llvm::MemoryBuffer> CompiledBuffer;
1105f757f3fSDimitry Andric   SourceMgrAdapter SMAdapter(
1115f757f3fSDimitry Andric       SM, SM.getDiagnostics(), diag::err_apinotes_message,
1125f757f3fSDimitry Andric       diag::warn_apinotes_message, diag::note_apinotes_message, std::nullopt);
1135f757f3fSDimitry Andric   llvm::raw_svector_ostream OS(APINotesBuffer);
1145f757f3fSDimitry Andric 
1155f757f3fSDimitry Andric   if (api_notes::compileAPINotes(Buffer, nullptr, OS,
1165f757f3fSDimitry Andric                                  SMAdapter.getDiagHandler(),
1175f757f3fSDimitry Andric                                  SMAdapter.getDiagContext()))
1185f757f3fSDimitry Andric     return nullptr;
1195f757f3fSDimitry Andric 
1205f757f3fSDimitry Andric   CompiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
1215f757f3fSDimitry Andric       StringRef(APINotesBuffer.data(), APINotesBuffer.size()));
1225f757f3fSDimitry Andric   auto Reader = APINotesReader::Create(std::move(CompiledBuffer), SwiftVersion);
1235f757f3fSDimitry Andric   assert(Reader && "Could not load the API notes we just generated?");
1245f757f3fSDimitry Andric   return Reader;
1255f757f3fSDimitry Andric }
1265f757f3fSDimitry Andric 
1275f757f3fSDimitry Andric bool APINotesManager::loadAPINotes(const DirectoryEntry *HeaderDir,
1285f757f3fSDimitry Andric                                    FileEntryRef APINotesFile) {
129cb14a3feSDimitry Andric   assert(!Readers.contains(HeaderDir));
1305f757f3fSDimitry Andric   if (auto Reader = loadAPINotes(APINotesFile)) {
1315f757f3fSDimitry Andric     Readers[HeaderDir] = Reader.release();
1325f757f3fSDimitry Andric     return false;
1335f757f3fSDimitry Andric   }
1345f757f3fSDimitry Andric 
1355f757f3fSDimitry Andric   Readers[HeaderDir] = nullptr;
1365f757f3fSDimitry Andric   return true;
1375f757f3fSDimitry Andric }
1385f757f3fSDimitry Andric 
1395f757f3fSDimitry Andric OptionalFileEntryRef
1405f757f3fSDimitry Andric APINotesManager::findAPINotesFile(DirectoryEntryRef Directory,
1415f757f3fSDimitry Andric                                   StringRef Basename, bool WantPublic) {
1425f757f3fSDimitry Andric   FileManager &FM = SM.getFileManager();
1435f757f3fSDimitry Andric 
1445f757f3fSDimitry Andric   llvm::SmallString<128> Path(Directory.getName());
1455f757f3fSDimitry Andric 
1465f757f3fSDimitry Andric   StringRef Suffix = WantPublic ? "" : "_private";
1475f757f3fSDimitry Andric 
1485f757f3fSDimitry Andric   // Look for the source API notes file.
1495f757f3fSDimitry Andric   llvm::sys::path::append(Path, llvm::Twine(Basename) + Suffix + "." +
1505f757f3fSDimitry Andric                                     SOURCE_APINOTES_EXTENSION);
1515f757f3fSDimitry Andric   return FM.getOptionalFileRef(Path, /*Open*/ true);
1525f757f3fSDimitry Andric }
1535f757f3fSDimitry Andric 
1545f757f3fSDimitry Andric OptionalDirectoryEntryRef APINotesManager::loadFrameworkAPINotes(
1555f757f3fSDimitry Andric     llvm::StringRef FrameworkPath, llvm::StringRef FrameworkName, bool Public) {
1565f757f3fSDimitry Andric   FileManager &FM = SM.getFileManager();
1575f757f3fSDimitry Andric 
1585f757f3fSDimitry Andric   llvm::SmallString<128> Path(FrameworkPath);
1595f757f3fSDimitry Andric   unsigned FrameworkNameLength = Path.size();
1605f757f3fSDimitry Andric 
1615f757f3fSDimitry Andric   StringRef Suffix = Public ? "" : "_private";
1625f757f3fSDimitry Andric 
1635f757f3fSDimitry Andric   // Form the path to the APINotes file.
1645f757f3fSDimitry Andric   llvm::sys::path::append(Path, "APINotes");
1655f757f3fSDimitry Andric   llvm::sys::path::append(Path, (llvm::Twine(FrameworkName) + Suffix + "." +
1665f757f3fSDimitry Andric                                  SOURCE_APINOTES_EXTENSION));
1675f757f3fSDimitry Andric 
1685f757f3fSDimitry Andric   // Try to open the APINotes file.
1695f757f3fSDimitry Andric   auto APINotesFile = FM.getOptionalFileRef(Path);
1705f757f3fSDimitry Andric   if (!APINotesFile)
1715f757f3fSDimitry Andric     return std::nullopt;
1725f757f3fSDimitry Andric 
1735f757f3fSDimitry Andric   // Form the path to the corresponding header directory.
1745f757f3fSDimitry Andric   Path.resize(FrameworkNameLength);
1755f757f3fSDimitry Andric   llvm::sys::path::append(Path, Public ? "Headers" : "PrivateHeaders");
1765f757f3fSDimitry Andric 
1775f757f3fSDimitry Andric   // Try to access the header directory.
1785f757f3fSDimitry Andric   auto HeaderDir = FM.getOptionalDirectoryRef(Path);
1795f757f3fSDimitry Andric   if (!HeaderDir)
1805f757f3fSDimitry Andric     return std::nullopt;
1815f757f3fSDimitry Andric 
1825f757f3fSDimitry Andric   // Try to load the API notes.
1835f757f3fSDimitry Andric   if (loadAPINotes(*HeaderDir, *APINotesFile))
1845f757f3fSDimitry Andric     return std::nullopt;
1855f757f3fSDimitry Andric 
1865f757f3fSDimitry Andric   // Success: return the header directory.
1875f757f3fSDimitry Andric   if (Public)
1885f757f3fSDimitry Andric     ++NumPublicFrameworkAPINotes;
1895f757f3fSDimitry Andric   else
1905f757f3fSDimitry Andric     ++NumPrivateFrameworkAPINotes;
1915f757f3fSDimitry Andric   return *HeaderDir;
1925f757f3fSDimitry Andric }
1935f757f3fSDimitry Andric 
1945f757f3fSDimitry Andric static void checkPrivateAPINotesName(DiagnosticsEngine &Diags,
1955f757f3fSDimitry Andric                                      const FileEntry *File, const Module *M) {
1965f757f3fSDimitry Andric   if (File->tryGetRealPathName().empty())
1975f757f3fSDimitry Andric     return;
1985f757f3fSDimitry Andric 
1995f757f3fSDimitry Andric   StringRef RealFileName =
2005f757f3fSDimitry Andric       llvm::sys::path::filename(File->tryGetRealPathName());
2015f757f3fSDimitry Andric   StringRef RealStem = llvm::sys::path::stem(RealFileName);
2025f757f3fSDimitry Andric   if (RealStem.ends_with("_private"))
2035f757f3fSDimitry Andric     return;
2045f757f3fSDimitry Andric 
2055f757f3fSDimitry Andric   unsigned DiagID = diag::warn_apinotes_private_case;
2065f757f3fSDimitry Andric   if (M->IsSystem)
2075f757f3fSDimitry Andric     DiagID = diag::warn_apinotes_private_case_system;
2085f757f3fSDimitry Andric 
2095f757f3fSDimitry Andric   Diags.Report(SourceLocation(), DiagID) << M->Name << RealFileName;
2105f757f3fSDimitry Andric }
2115f757f3fSDimitry Andric 
2125f757f3fSDimitry Andric /// \returns true if any of \p module's immediate submodules are defined in a
2135f757f3fSDimitry Andric /// private module map
2145f757f3fSDimitry Andric static bool hasPrivateSubmodules(const Module *M) {
2155f757f3fSDimitry Andric   return llvm::any_of(M->submodules(), [](const Module *Submodule) {
2165f757f3fSDimitry Andric     return Submodule->ModuleMapIsPrivate;
2175f757f3fSDimitry Andric   });
2185f757f3fSDimitry Andric }
2195f757f3fSDimitry Andric 
2205f757f3fSDimitry Andric llvm::SmallVector<FileEntryRef, 2>
2215f757f3fSDimitry Andric APINotesManager::getCurrentModuleAPINotes(Module *M, bool LookInModule,
2225f757f3fSDimitry Andric                                           ArrayRef<std::string> SearchPaths) {
2235f757f3fSDimitry Andric   FileManager &FM = SM.getFileManager();
2245f757f3fSDimitry Andric   auto ModuleName = M->getTopLevelModuleName();
225*0fca6ea1SDimitry Andric   auto ExportedModuleName = M->getTopLevelModule()->ExportAsModule;
2265f757f3fSDimitry Andric   llvm::SmallVector<FileEntryRef, 2> APINotes;
2275f757f3fSDimitry Andric 
2285f757f3fSDimitry Andric   // First, look relative to the module itself.
229*0fca6ea1SDimitry Andric   if (LookInModule && M->Directory) {
2305f757f3fSDimitry Andric     // Local function to try loading an API notes file in the given directory.
2315f757f3fSDimitry Andric     auto tryAPINotes = [&](DirectoryEntryRef Dir, bool WantPublic) {
2325f757f3fSDimitry Andric       if (auto File = findAPINotesFile(Dir, ModuleName, WantPublic)) {
2335f757f3fSDimitry Andric         if (!WantPublic)
2345f757f3fSDimitry Andric           checkPrivateAPINotesName(SM.getDiagnostics(), *File, M);
2355f757f3fSDimitry Andric 
2365f757f3fSDimitry Andric         APINotes.push_back(*File);
2375f757f3fSDimitry Andric       }
238*0fca6ea1SDimitry Andric       // If module FooCore is re-exported through module Foo, try Foo.apinotes.
239*0fca6ea1SDimitry Andric       if (!ExportedModuleName.empty())
240*0fca6ea1SDimitry Andric         if (auto File = findAPINotesFile(Dir, ExportedModuleName, WantPublic))
241*0fca6ea1SDimitry Andric           APINotes.push_back(*File);
2425f757f3fSDimitry Andric     };
2435f757f3fSDimitry Andric 
2445f757f3fSDimitry Andric     if (M->IsFramework) {
2455f757f3fSDimitry Andric       // For frameworks, we search in the "Headers" or "PrivateHeaders"
2465f757f3fSDimitry Andric       // subdirectory.
2475f757f3fSDimitry Andric       //
2485f757f3fSDimitry Andric       // Public modules:
2495f757f3fSDimitry Andric       // - Headers/Foo.apinotes
2505f757f3fSDimitry Andric       // - PrivateHeaders/Foo_private.apinotes (if there are private submodules)
2515f757f3fSDimitry Andric       // Private modules:
2525f757f3fSDimitry Andric       // - PrivateHeaders/Bar.apinotes (except that 'Bar' probably already has
2535f757f3fSDimitry Andric       //   the word "Private" in it in practice)
2545f757f3fSDimitry Andric       llvm::SmallString<128> Path(M->Directory->getName());
2555f757f3fSDimitry Andric 
2565f757f3fSDimitry Andric       if (!M->ModuleMapIsPrivate) {
2575f757f3fSDimitry Andric         unsigned PathLen = Path.size();
2585f757f3fSDimitry Andric 
2595f757f3fSDimitry Andric         llvm::sys::path::append(Path, "Headers");
2605f757f3fSDimitry Andric         if (auto APINotesDir = FM.getOptionalDirectoryRef(Path))
2615f757f3fSDimitry Andric           tryAPINotes(*APINotesDir, /*wantPublic=*/true);
2625f757f3fSDimitry Andric 
2635f757f3fSDimitry Andric         Path.resize(PathLen);
2645f757f3fSDimitry Andric       }
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric       if (M->ModuleMapIsPrivate || hasPrivateSubmodules(M)) {
2675f757f3fSDimitry Andric         llvm::sys::path::append(Path, "PrivateHeaders");
2685f757f3fSDimitry Andric         if (auto PrivateAPINotesDir = FM.getOptionalDirectoryRef(Path))
2695f757f3fSDimitry Andric           tryAPINotes(*PrivateAPINotesDir,
2705f757f3fSDimitry Andric                       /*wantPublic=*/M->ModuleMapIsPrivate);
2715f757f3fSDimitry Andric       }
2725f757f3fSDimitry Andric     } else {
2735f757f3fSDimitry Andric       // Public modules:
2745f757f3fSDimitry Andric       // - Foo.apinotes
2755f757f3fSDimitry Andric       // - Foo_private.apinotes (if there are private submodules)
2765f757f3fSDimitry Andric       // Private modules:
2775f757f3fSDimitry Andric       // - Bar.apinotes (except that 'Bar' probably already has the word
2785f757f3fSDimitry Andric       //   "Private" in it in practice)
2795f757f3fSDimitry Andric       tryAPINotes(*M->Directory, /*wantPublic=*/true);
2805f757f3fSDimitry Andric       if (!M->ModuleMapIsPrivate && hasPrivateSubmodules(M))
2815f757f3fSDimitry Andric         tryAPINotes(*M->Directory, /*wantPublic=*/false);
2825f757f3fSDimitry Andric     }
2835f757f3fSDimitry Andric 
2845f757f3fSDimitry Andric     if (!APINotes.empty())
2855f757f3fSDimitry Andric       return APINotes;
2865f757f3fSDimitry Andric   }
2875f757f3fSDimitry Andric 
2885f757f3fSDimitry Andric   // Second, look for API notes for this module in the module API
2895f757f3fSDimitry Andric   // notes search paths.
2905f757f3fSDimitry Andric   for (const auto &SearchPath : SearchPaths) {
2915f757f3fSDimitry Andric     if (auto SearchDir = FM.getOptionalDirectoryRef(SearchPath)) {
2925f757f3fSDimitry Andric       if (auto File = findAPINotesFile(*SearchDir, ModuleName)) {
2935f757f3fSDimitry Andric         APINotes.push_back(*File);
2945f757f3fSDimitry Andric         return APINotes;
2955f757f3fSDimitry Andric       }
2965f757f3fSDimitry Andric     }
2975f757f3fSDimitry Andric   }
2985f757f3fSDimitry Andric 
2995f757f3fSDimitry Andric   // Didn't find any API notes.
3005f757f3fSDimitry Andric   return APINotes;
3015f757f3fSDimitry Andric }
3025f757f3fSDimitry Andric 
3035f757f3fSDimitry Andric bool APINotesManager::loadCurrentModuleAPINotes(
3045f757f3fSDimitry Andric     Module *M, bool LookInModule, ArrayRef<std::string> SearchPaths) {
3055f757f3fSDimitry Andric   assert(!CurrentModuleReaders[ReaderKind::Public] &&
3065f757f3fSDimitry Andric          "Already loaded API notes for the current module?");
3075f757f3fSDimitry Andric 
3085f757f3fSDimitry Andric   auto APINotes = getCurrentModuleAPINotes(M, LookInModule, SearchPaths);
3095f757f3fSDimitry Andric   unsigned NumReaders = 0;
3105f757f3fSDimitry Andric   for (auto File : APINotes) {
3115f757f3fSDimitry Andric     CurrentModuleReaders[NumReaders++] = loadAPINotes(File).release();
3125f757f3fSDimitry Andric     if (!getCurrentModuleReaders().empty())
3135f757f3fSDimitry Andric       M->APINotesFile = File.getName().str();
3145f757f3fSDimitry Andric   }
3155f757f3fSDimitry Andric 
3165f757f3fSDimitry Andric   return NumReaders > 0;
3175f757f3fSDimitry Andric }
3185f757f3fSDimitry Andric 
3195f757f3fSDimitry Andric bool APINotesManager::loadCurrentModuleAPINotesFromBuffer(
3205f757f3fSDimitry Andric     ArrayRef<StringRef> Buffers) {
3215f757f3fSDimitry Andric   unsigned NumReader = 0;
3225f757f3fSDimitry Andric   for (auto Buf : Buffers) {
3235f757f3fSDimitry Andric     auto Reader = loadAPINotes(Buf);
3245f757f3fSDimitry Andric     assert(Reader && "Could not load the API notes we just generated?");
3255f757f3fSDimitry Andric 
3265f757f3fSDimitry Andric     CurrentModuleReaders[NumReader++] = Reader.release();
3275f757f3fSDimitry Andric   }
3285f757f3fSDimitry Andric   return NumReader;
3295f757f3fSDimitry Andric }
3305f757f3fSDimitry Andric 
3315f757f3fSDimitry Andric llvm::SmallVector<APINotesReader *, 2>
3325f757f3fSDimitry Andric APINotesManager::findAPINotes(SourceLocation Loc) {
3335f757f3fSDimitry Andric   llvm::SmallVector<APINotesReader *, 2> Results;
3345f757f3fSDimitry Andric 
3355f757f3fSDimitry Andric   // If there are readers for the current module, return them.
3365f757f3fSDimitry Andric   if (!getCurrentModuleReaders().empty()) {
3375f757f3fSDimitry Andric     Results.append(getCurrentModuleReaders().begin(),
3385f757f3fSDimitry Andric                    getCurrentModuleReaders().end());
3395f757f3fSDimitry Andric     return Results;
3405f757f3fSDimitry Andric   }
3415f757f3fSDimitry Andric 
3425f757f3fSDimitry Andric   // If we're not allowed to implicitly load API notes files, we're done.
3435f757f3fSDimitry Andric   if (!ImplicitAPINotes)
3445f757f3fSDimitry Andric     return Results;
3455f757f3fSDimitry Andric 
3465f757f3fSDimitry Andric   // If we don't have source location information, we're done.
3475f757f3fSDimitry Andric   if (Loc.isInvalid())
3485f757f3fSDimitry Andric     return Results;
3495f757f3fSDimitry Andric 
3505f757f3fSDimitry Andric   // API notes are associated with the expansion location. Retrieve the
3515f757f3fSDimitry Andric   // file for this location.
3525f757f3fSDimitry Andric   SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
3535f757f3fSDimitry Andric   FileID ID = SM.getFileID(ExpansionLoc);
3545f757f3fSDimitry Andric   if (ID.isInvalid())
3555f757f3fSDimitry Andric     return Results;
3565f757f3fSDimitry Andric   OptionalFileEntryRef File = SM.getFileEntryRefForID(ID);
3575f757f3fSDimitry Andric   if (!File)
3585f757f3fSDimitry Andric     return Results;
3595f757f3fSDimitry Andric 
3605f757f3fSDimitry Andric   // Look for API notes in the directory corresponding to this file, or one of
3615f757f3fSDimitry Andric   // its its parent directories.
3625f757f3fSDimitry Andric   OptionalDirectoryEntryRef Dir = File->getDir();
3635f757f3fSDimitry Andric   FileManager &FileMgr = SM.getFileManager();
3645f757f3fSDimitry Andric   llvm::SetVector<const DirectoryEntry *,
3655f757f3fSDimitry Andric                   SmallVector<const DirectoryEntry *, 4>,
3665f757f3fSDimitry Andric                   llvm::SmallPtrSet<const DirectoryEntry *, 4>>
3675f757f3fSDimitry Andric       DirsVisited;
3685f757f3fSDimitry Andric   do {
3695f757f3fSDimitry Andric     // Look for an API notes reader for this header search directory.
3705f757f3fSDimitry Andric     auto Known = Readers.find(*Dir);
3715f757f3fSDimitry Andric 
3725f757f3fSDimitry Andric     // If we already know the answer, chase it.
3735f757f3fSDimitry Andric     if (Known != Readers.end()) {
3745f757f3fSDimitry Andric       ++NumDirectoryCacheHits;
3755f757f3fSDimitry Andric 
3765f757f3fSDimitry Andric       // We've been redirected to another directory for answers. Follow it.
3775f757f3fSDimitry Andric       if (Known->second && Known->second.is<DirectoryEntryRef>()) {
3785f757f3fSDimitry Andric         DirsVisited.insert(*Dir);
3795f757f3fSDimitry Andric         Dir = Known->second.get<DirectoryEntryRef>();
3805f757f3fSDimitry Andric         continue;
3815f757f3fSDimitry Andric       }
3825f757f3fSDimitry Andric 
3835f757f3fSDimitry Andric       // We have the answer.
3845f757f3fSDimitry Andric       if (auto Reader = Known->second.dyn_cast<APINotesReader *>())
3855f757f3fSDimitry Andric         Results.push_back(Reader);
3865f757f3fSDimitry Andric       break;
3875f757f3fSDimitry Andric     }
3885f757f3fSDimitry Andric 
3895f757f3fSDimitry Andric     // Look for API notes corresponding to this directory.
3905f757f3fSDimitry Andric     StringRef Path = Dir->getName();
3915f757f3fSDimitry Andric     if (llvm::sys::path::extension(Path) == ".framework") {
3925f757f3fSDimitry Andric       // If this is a framework directory, check whether there are API notes
3935f757f3fSDimitry Andric       // in the APINotes subdirectory.
3945f757f3fSDimitry Andric       auto FrameworkName = llvm::sys::path::stem(Path);
3955f757f3fSDimitry Andric       ++NumFrameworksSearched;
3965f757f3fSDimitry Andric 
3975f757f3fSDimitry Andric       // Look for API notes for both the public and private headers.
3985f757f3fSDimitry Andric       OptionalDirectoryEntryRef PublicDir =
3995f757f3fSDimitry Andric           loadFrameworkAPINotes(Path, FrameworkName, /*Public=*/true);
4005f757f3fSDimitry Andric       OptionalDirectoryEntryRef PrivateDir =
4015f757f3fSDimitry Andric           loadFrameworkAPINotes(Path, FrameworkName, /*Public=*/false);
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric       if (PublicDir || PrivateDir) {
4045f757f3fSDimitry Andric         // We found API notes: don't ever look past the framework directory.
4055f757f3fSDimitry Andric         Readers[*Dir] = nullptr;
4065f757f3fSDimitry Andric 
4075f757f3fSDimitry Andric         // Pretend we found the result in the public or private directory,
4085f757f3fSDimitry Andric         // as appropriate. All headers should be in one of those two places,
4095f757f3fSDimitry Andric         // but be defensive here.
4105f757f3fSDimitry Andric         if (!DirsVisited.empty()) {
4115f757f3fSDimitry Andric           if (PublicDir && DirsVisited.back() == *PublicDir) {
4125f757f3fSDimitry Andric             DirsVisited.pop_back();
4135f757f3fSDimitry Andric             Dir = *PublicDir;
4145f757f3fSDimitry Andric           } else if (PrivateDir && DirsVisited.back() == *PrivateDir) {
4155f757f3fSDimitry Andric             DirsVisited.pop_back();
4165f757f3fSDimitry Andric             Dir = *PrivateDir;
4175f757f3fSDimitry Andric           }
4185f757f3fSDimitry Andric         }
4195f757f3fSDimitry Andric 
4205f757f3fSDimitry Andric         // Grab the result.
4215f757f3fSDimitry Andric         if (auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
4225f757f3fSDimitry Andric           Results.push_back(Reader);
4235f757f3fSDimitry Andric         break;
4245f757f3fSDimitry Andric       }
4255f757f3fSDimitry Andric     } else {
4265f757f3fSDimitry Andric       // Look for an APINotes file in this directory.
4275f757f3fSDimitry Andric       llvm::SmallString<128> APINotesPath(Dir->getName());
4285f757f3fSDimitry Andric       llvm::sys::path::append(
4295f757f3fSDimitry Andric           APINotesPath, (llvm::Twine("APINotes.") + SOURCE_APINOTES_EXTENSION));
4305f757f3fSDimitry Andric 
4315f757f3fSDimitry Andric       // If there is an API notes file here, try to load it.
4325f757f3fSDimitry Andric       ++NumDirectoriesSearched;
4335f757f3fSDimitry Andric       if (auto APINotesFile = FileMgr.getOptionalFileRef(APINotesPath)) {
4345f757f3fSDimitry Andric         if (!loadAPINotes(*Dir, *APINotesFile)) {
4355f757f3fSDimitry Andric           ++NumHeaderAPINotes;
4365f757f3fSDimitry Andric           if (auto Reader = Readers[*Dir].dyn_cast<APINotesReader *>())
4375f757f3fSDimitry Andric             Results.push_back(Reader);
4385f757f3fSDimitry Andric           break;
4395f757f3fSDimitry Andric         }
4405f757f3fSDimitry Andric       }
4415f757f3fSDimitry Andric     }
4425f757f3fSDimitry Andric 
4435f757f3fSDimitry Andric     // We didn't find anything. Look at the parent directory.
4445f757f3fSDimitry Andric     if (!DirsVisited.insert(*Dir)) {
4455f757f3fSDimitry Andric       Dir = std::nullopt;
4465f757f3fSDimitry Andric       break;
4475f757f3fSDimitry Andric     }
4485f757f3fSDimitry Andric 
4495f757f3fSDimitry Andric     StringRef ParentPath = llvm::sys::path::parent_path(Path);
4505f757f3fSDimitry Andric     while (llvm::sys::path::stem(ParentPath) == "..")
4515f757f3fSDimitry Andric       ParentPath = llvm::sys::path::parent_path(ParentPath);
4525f757f3fSDimitry Andric 
4535f757f3fSDimitry Andric     Dir = ParentPath.empty() ? std::nullopt
4545f757f3fSDimitry Andric                              : FileMgr.getOptionalDirectoryRef(ParentPath);
4555f757f3fSDimitry Andric   } while (Dir);
4565f757f3fSDimitry Andric 
4575f757f3fSDimitry Andric   // Path compression for all of the directories we visited, redirecting
4585f757f3fSDimitry Andric   // them to the directory we ended on. If no API notes were found, the
4595f757f3fSDimitry Andric   // resulting directory will be NULL, indicating no API notes.
4605f757f3fSDimitry Andric   for (const auto Visited : DirsVisited)
4615f757f3fSDimitry Andric     Readers[Visited] = Dir ? ReaderEntry(*Dir) : ReaderEntry();
4625f757f3fSDimitry Andric 
4635f757f3fSDimitry Andric   return Results;
4645f757f3fSDimitry Andric }
465