Skip to content

Commit c86110a

Browse files
[IncludeTree] Support APINotes with IncludeTree
Add support for APINotes when using include-tree. Loading APINotes during dependency scanning and store the APINotes as part of the IncludeTree so it can be loaded directly from IncludeTree during compilation. Only support `-fapinotes-module` and emit error when the old deprecated `-fapinotes` is used because that option uses an expensive and unbounded search for APNotes based on SourceLoc of Decls.
1 parent bb2db20 commit c86110a

File tree

11 files changed

+411
-36
lines changed

11 files changed

+411
-36
lines changed

clang/include/clang/APINotes/APINotesManager.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ class APINotesManager {
7777
/// a failure.
7878
std::unique_ptr<APINotesReader> loadAPINotes(const FileEntry *apiNotesFile);
7979

80+
/// Load the API notes associated with the given buffer, whether it is
81+
/// the binary or source form of API notes.
82+
///
83+
/// \returns the API notes reader for this file, or null if there is
84+
/// a failure.
85+
std::unique_ptr<APINotesReader> loadAPINotes(StringRef Buffer);
86+
8087
/// Load the given API notes file for the given header directory.
8188
///
8289
/// \param HeaderDir The directory at which we
@@ -126,6 +133,25 @@ class APINotesManager {
126133
bool lookInModule,
127134
ArrayRef<std::string> searchPaths);
128135

136+
/// Get FileEntry for the APINotes of the current module.
137+
///
138+
/// \param module The current module.
139+
/// \param lookInModule Whether to look inside the module itself.
140+
/// \param searchPaths The paths in which we should search for API notes
141+
/// for the current module.
142+
///
143+
/// \returns a vector of FileEntry where APINotes files are.
144+
llvm::SmallVector<const FileEntry *, 2>
145+
getCurrentModuleAPINotes(Module *module, bool lookInModule,
146+
ArrayRef<std::string> searchPaths);
147+
148+
/// Load Compiled API notes for current module.
149+
///
150+
/// \param Buffers Array of compiled API notes.
151+
///
152+
/// \returns true if API notes were successfully loaded, \c false otherwise.
153+
bool loadCurrentModuleAPINotesFromBuffer(ArrayRef<StringRef> Buffers);
154+
129155
/// Retrieve the set of API notes readers for the current module.
130156
ArrayRef<APINotesReader *> getCurrentModuleReaders() const {
131157
unsigned numReaders = static_cast<unsigned>(CurrentModuleReaders[0] != nullptr) +

clang/include/clang/Basic/DiagnosticCASKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def err_cas_cannot_parse_include_tree_id : Error<
4040
"CAS cannot parse include-tree-id '%0'">, DefaultFatal;
4141
def err_cas_missing_include_tree_id : Error<
4242
"CAS missing expected include-tree '%0'">, DefaultFatal;
43+
def err_cas_cannot_load_api_notes_include_tree : Error<
44+
"cannot load APINotes from include-tree-id '%0'">, DefaultFatal;
4345

4446
def warn_clang_cache_disabled_caching: Warning<
4547
"caching disabled because %0">,

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,8 @@ def err_drv_target_variant_invalid : Error<
680680

681681
def err_drv_inputs_and_include_tree : Error<
682682
"passing input files is incompatible with '-fcas-include-tree'">;
683+
def err_drv_incompatible_option_include_tree : Error<
684+
"passing incompatible option '%0' with '-fcas-include-tree'">;
683685

684686
def err_drv_invalid_directx_shader_module : Error<
685687
"invalid profile : %0">;

clang/include/clang/CAS/IncludeTree.h

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class IncludeTree : public IncludeTreeBase<IncludeTree> {
5757
class Module;
5858
class ModuleImport;
5959
class ModuleMap;
60+
class APINotes;
6061

6162
Expected<File> getBaseFile();
6263

@@ -644,6 +645,46 @@ class IncludeTree::ModuleMap : public IncludeTreeBase<ModuleMap> {
644645
friend class IncludeTreeRoot;
645646
};
646647

648+
/// A list of \c APINotes that is compiled and loaded.
649+
class IncludeTree::APINotes : public IncludeTreeBase<APINotes> {
650+
public:
651+
static constexpr StringRef getNodeKind() { return "APIN"; }
652+
653+
llvm::Error
654+
forEachAPINotes(llvm::function_ref<llvm::Error(StringRef)> Callback);
655+
656+
static Expected<APINotes> create(ObjectStore &DB,
657+
ArrayRef<ObjectRef> APINoteList);
658+
659+
static Expected<APINotes> get(ObjectStore &CAS, ObjectRef Ref);
660+
661+
llvm::Error print(llvm::raw_ostream &OS, unsigned Indent = 0);
662+
663+
private:
664+
friend class IncludeTreeBase<APINotes>;
665+
friend class IncludeTreeRoot;
666+
667+
explicit APINotes(ObjectProxy Node) : IncludeTreeBase(std::move(Node)) {
668+
assert(isValid(*this));
669+
}
670+
671+
static bool isValid(const ObjectProxy &Node) {
672+
if (!IncludeTreeBase::isValid(Node))
673+
return false;
674+
IncludeTreeBase Base(Node);
675+
return Base.getData().empty() && Base.getNumReferences() < 2;
676+
}
677+
678+
static bool isValid(ObjectStore &CAS, ObjectRef Ref) {
679+
auto Node = CAS.getProxy(Ref);
680+
if (!Node) {
681+
llvm::consumeError(Node.takeError());
682+
return false;
683+
}
684+
return isValid(*Node);
685+
}
686+
};
687+
647688
/// Represents the include-tree result for a translation unit.
648689
class IncludeTreeRoot : public IncludeTreeBase<IncludeTreeRoot> {
649690
public:
@@ -665,6 +706,12 @@ class IncludeTreeRoot : public IncludeTreeBase<IncludeTreeRoot> {
665706
return std::nullopt;
666707
}
667708

709+
Optional<ObjectRef> getAPINotesRef() const {
710+
if (auto Index = getAPINotesRefIndex())
711+
return getReference(*Index);
712+
return std::nullopt;
713+
}
714+
668715
Expected<IncludeTree> getMainFileTree() {
669716
auto Node = getCAS().getProxy(getMainFileTreeRef());
670717
if (!Node)
@@ -699,10 +746,20 @@ class IncludeTreeRoot : public IncludeTreeBase<IncludeTreeRoot> {
699746
return std::nullopt;
700747
}
701748

749+
Expected<Optional<IncludeTree::APINotes>> getAPINotes() {
750+
if (Optional<ObjectRef> Ref = getAPINotesRef()) {
751+
auto Node = getCAS().getProxy(*Ref);
752+
if (!Node)
753+
return Node.takeError();
754+
return IncludeTree::APINotes(*Node);
755+
}
756+
return std::nullopt;
757+
}
758+
702759
static Expected<IncludeTreeRoot>
703760
create(ObjectStore &DB, ObjectRef MainFileTree, ObjectRef FileList,
704-
Optional<ObjectRef> PCHRef,
705-
Optional<ObjectRef> ModuleMapRef);
761+
Optional<ObjectRef> PCHRef, Optional<ObjectRef> ModuleMapRef,
762+
Optional<ObjectRef> APINotesRef);
706763

707764
static Expected<IncludeTreeRoot> get(ObjectStore &DB, ObjectRef Ref);
708765

@@ -729,6 +786,7 @@ class IncludeTreeRoot : public IncludeTreeBase<IncludeTreeRoot> {
729786

730787
std::optional<unsigned> getPCHRefIndex() const;
731788
std::optional<unsigned> getModuleMapRefIndex() const;
789+
std::optional<unsigned> getAPINotesRefIndex() const;
732790

733791
explicit IncludeTreeRoot(ObjectProxy Node)
734792
: IncludeTreeBase(std::move(Node)) {

clang/lib/APINotes/APINotesManager.cpp

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
#include "clang/Basic/Version.h"
2424
#include "llvm/ADT/APInt.h"
2525
#include "llvm/ADT/Hashing.h"
26+
#include "llvm/ADT/SmallVector.h"
2627
#include "llvm/ADT/Statistic.h"
2728
#include "llvm/ADT/SetVector.h"
2829
#include "llvm/ADT/SmallPtrSet.h"
30+
#include "llvm/Support/MemoryBuffer.h"
2931
#include "llvm/Support/Path.h"
3032
#include "llvm/Support/PrettyStackTrace.h"
3133
#include <sys/stat.h>
@@ -119,6 +121,27 @@ APINotesManager::loadAPINotes(const FileEntry *apiNotesFile) {
119121
return reader;
120122
}
121123

124+
std::unique_ptr<APINotesReader>
125+
APINotesManager::loadAPINotes(StringRef Buffer) {
126+
llvm::SmallVector<char, 1024> apiNotesBuffer;
127+
std::unique_ptr<llvm::MemoryBuffer> compiledBuffer;
128+
SourceMgrAdapter srcMgrAdapter(
129+
SourceMgr, SourceMgr.getDiagnostics(), diag::err_apinotes_message,
130+
diag::warn_apinotes_message, diag::note_apinotes_message, nullptr);
131+
llvm::raw_svector_ostream OS(apiNotesBuffer);
132+
133+
if (api_notes::compileAPINotes(Buffer, nullptr, OS,
134+
srcMgrAdapter.getDiagHandler(),
135+
srcMgrAdapter.getDiagContext()))
136+
return nullptr;
137+
138+
compiledBuffer = llvm::MemoryBuffer::getMemBufferCopy(
139+
StringRef(apiNotesBuffer.data(), apiNotesBuffer.size()));
140+
auto reader = APINotesReader::get(std::move(compiledBuffer), SwiftVersion);
141+
assert(reader && "Could not load the API notes we just generated?");
142+
return reader;
143+
}
144+
122145
bool APINotesManager::loadAPINotes(const DirectoryEntry *HeaderDir,
123146
const FileEntry *APINotesFile) {
124147
assert(Readers.find(HeaderDir) == Readers.end());
@@ -226,33 +249,21 @@ static bool hasPrivateSubmodules(const Module *module) {
226249
});
227250
}
228251

229-
bool APINotesManager::loadCurrentModuleAPINotes(
252+
llvm::SmallVector<const FileEntry *, 2> APINotesManager::getCurrentModuleAPINotes(
230253
Module *module, bool lookInModule, ArrayRef<std::string> searchPaths) {
231-
assert(!CurrentModuleReaders[0] &&
232-
"Already loaded API notes for the current module?");
233-
234254
FileManager &fileMgr = SourceMgr.getFileManager();
235255
auto moduleName = module->getTopLevelModuleName();
256+
llvm::SmallVector<const FileEntry *, 2> APINotes;
236257

237258
// First, look relative to the module itself.
238259
if (lookInModule) {
239-
bool foundAny = false;
240-
unsigned numReaders = 0;
241-
242260
// Local function to try loading an API notes file in the given directory.
243261
auto tryAPINotes = [&](const DirectoryEntry *dir, bool wantPublic) {
244-
if (auto file = findAPINotesFile(dir, moduleName, wantPublic)) {
245-
foundAny = true;
246-
262+
if (auto *file = findAPINotesFile(dir, moduleName, wantPublic)) {
247263
if (!wantPublic)
248264
checkPrivateAPINotesName(SourceMgr.getDiagnostics(), file, module);
249265

250-
// Try to load the API notes file.
251-
CurrentModuleReaders[numReaders] = loadAPINotes(file).release();
252-
if (CurrentModuleReaders[numReaders]) {
253-
module->APINotesFile = file->getName().str();
254-
++numReaders;
255-
}
266+
APINotes.push_back(file);
256267
}
257268
};
258269

@@ -298,27 +309,52 @@ bool APINotesManager::loadCurrentModuleAPINotes(
298309
tryAPINotes(module->Directory, /*wantPublic=*/false);
299310
}
300311

301-
if (foundAny)
302-
return numReaders > 0;
312+
if (!APINotes.empty())
313+
return APINotes;
303314
}
304315

305316
// Second, look for API notes for this module in the module API
306317
// notes search paths.
307318
for (const auto &searchPath : searchPaths) {
308319
if (auto searchDir = fileMgr.getDirectory(searchPath)) {
309-
if (auto file = findAPINotesFile(*searchDir, moduleName)) {
310-
CurrentModuleReaders[0] = loadAPINotes(file).release();
311-
if (!getCurrentModuleReaders().empty()) {
312-
module->APINotesFile = file->getName().str();
313-
return true;
314-
}
315-
return false;
320+
if (auto *file = findAPINotesFile(*searchDir, moduleName)) {
321+
APINotes.push_back(file);
322+
return APINotes;
316323
}
317324
}
318325
}
319326

320327
// Didn't find any API notes.
321-
return false;
328+
return APINotes;
329+
}
330+
331+
332+
bool APINotesManager::loadCurrentModuleAPINotes(
333+
Module *module, bool lookInModule, ArrayRef<std::string> searchPaths) {
334+
assert(!CurrentModuleReaders[0] &&
335+
"Already loaded API notes for the current module?");
336+
337+
auto APINotes = getCurrentModuleAPINotes(module, lookInModule, searchPaths);
338+
unsigned numReaders = 0;
339+
for (auto *file : APINotes) {
340+
CurrentModuleReaders[numReaders++] = loadAPINotes(file).release();
341+
if (!getCurrentModuleReaders().empty())
342+
module->APINotesFile = file->getName().str();
343+
}
344+
345+
return numReaders > 0;
346+
}
347+
348+
bool APINotesManager::loadCurrentModuleAPINotesFromBuffer(
349+
ArrayRef<StringRef> Buffers) {
350+
unsigned NumReader = 0;
351+
for (auto Buf : Buffers) {
352+
auto Reader = loadAPINotes(Buf);
353+
assert(Reader && "Could not load the API notes we just generated?");
354+
355+
CurrentModuleReaders[NumReader++] = Reader.release();
356+
}
357+
return NumReader;
322358
}
323359

324360
llvm::SmallVector<APINotesReader *, 2> APINotesManager::findAPINotes(SourceLocation Loc) {

0 commit comments

Comments
 (0)