aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-09-02 21:17:18 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-12-08 17:34:50 +0000
commit06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e (patch)
tree62f873df87c7c675557a179e0c4c83fe9f3087bc /contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
parentcf037972ea8863e2bab7461d77345367d2c1e054 (diff)
parent7fa27ce4a07f19b07799a767fc29416f3b625afb (diff)
Diffstat (limited to 'contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp194
1 files changed, 170 insertions, 24 deletions
diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index 644845efb819..eb533a934367 100644
--- a/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -12,8 +12,10 @@
///
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -26,13 +28,16 @@
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -219,11 +224,48 @@ private:
llvm::DenseSet<const FileEntry *> ExternalFileEntries;
};
+struct BatchExtractAPIVisitor : ExtractAPIVisitor<BatchExtractAPIVisitor> {
+ bool shouldDeclBeIncluded(const Decl *D) const {
+ bool ShouldBeIncluded = true;
+ // Check that we have the definition for redeclarable types.
+ if (auto *TD = llvm::dyn_cast<TagDecl>(D))
+ ShouldBeIncluded = TD->isThisDeclarationADefinition();
+ else if (auto *Interface = llvm::dyn_cast<ObjCInterfaceDecl>(D))
+ ShouldBeIncluded = Interface->isThisDeclarationADefinition();
+ else if (auto *Protocol = llvm::dyn_cast<ObjCProtocolDecl>(D))
+ ShouldBeIncluded = Protocol->isThisDeclarationADefinition();
+
+ ShouldBeIncluded = ShouldBeIncluded && LCF(D->getLocation());
+ return ShouldBeIncluded;
+ }
+
+ BatchExtractAPIVisitor(LocationFileChecker &LCF, ASTContext &Context,
+ APISet &API)
+ : ExtractAPIVisitor<BatchExtractAPIVisitor>(Context, API), LCF(LCF) {}
+
+private:
+ LocationFileChecker &LCF;
+};
+
+class WrappingExtractAPIConsumer : public ASTConsumer {
+public:
+ WrappingExtractAPIConsumer(ASTContext &Context, APISet &API)
+ : Visitor(Context, API) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ // Use ExtractAPIVisitor to traverse symbol declarations in the context.
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ }
+
+private:
+ ExtractAPIVisitor<> Visitor;
+};
+
class ExtractAPIConsumer : public ASTConsumer {
public:
ExtractAPIConsumer(ASTContext &Context,
std::unique_ptr<LocationFileChecker> LCF, APISet &API)
- : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {}
+ : Visitor(*LCF, Context, API), LCF(std::move(LCF)) {}
void HandleTranslationUnit(ASTContext &Context) override {
// Use ExtractAPIVisitor to traverse symbol declarations in the context.
@@ -231,15 +273,14 @@ public:
}
private:
- ExtractAPIVisitor Visitor;
+ BatchExtractAPIVisitor Visitor;
std::unique_ptr<LocationFileChecker> LCF;
};
class MacroCallback : public PPCallbacks {
public:
- MacroCallback(const SourceManager &SM, LocationFileChecker &LCF, APISet &API,
- Preprocessor &PP)
- : SM(SM), LCF(LCF), API(API), PP(PP) {}
+ MacroCallback(const SourceManager &SM, APISet &API, Preprocessor &PP)
+ : SM(SM), API(API), PP(PP) {}
void MacroDefined(const Token &MacroNameToken,
const MacroDirective *MD) override {
@@ -279,7 +320,7 @@ public:
if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
continue;
- if (!LCF(PM.MacroNameToken.getLocation()))
+ if (!shouldMacroBeIncluded(PM))
continue;
StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
@@ -297,7 +338,7 @@ public:
PendingMacros.clear();
}
-private:
+protected:
struct PendingMacro {
Token MacroNameToken;
const MacroDirective *MD;
@@ -306,18 +347,58 @@ private:
: MacroNameToken(MacroNameToken), MD(MD) {}
};
+ virtual bool shouldMacroBeIncluded(const PendingMacro &PM) { return true; }
+
const SourceManager &SM;
- LocationFileChecker &LCF;
APISet &API;
Preprocessor &PP;
llvm::SmallVector<PendingMacro> PendingMacros;
};
+class APIMacroCallback : public MacroCallback {
+public:
+ APIMacroCallback(const SourceManager &SM, APISet &API, Preprocessor &PP,
+ LocationFileChecker &LCF)
+ : MacroCallback(SM, API, PP), LCF(LCF) {}
+
+ bool shouldMacroBeIncluded(const PendingMacro &PM) override {
+ // Do not include macros from external files
+ return LCF(PM.MacroNameToken.getLocation());
+ }
+
+private:
+ LocationFileChecker &LCF;
+};
+
} // namespace
+void ExtractAPIActionBase::ImplEndSourceFileAction() {
+ if (!OS)
+ return;
+
+ // Setup a SymbolGraphSerializer to write out collected API information in
+ // the Symbol Graph format.
+ // FIXME: Make the kind of APISerializer configurable.
+ SymbolGraphSerializer SGSerializer(*API, IgnoresList);
+ SGSerializer.serialize(*OS);
+ OS.reset();
+}
+
+std::unique_ptr<raw_pwrite_stream>
+ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
+ std::unique_ptr<raw_pwrite_stream> OS;
+ OS = CI.createDefaultOutputFile(/*Binary=*/false, InFile,
+ /*Extension=*/"json",
+ /*RemoveFileOnSignal=*/false);
+ if (!OS)
+ return nullptr;
+ return OS;
+}
+
std::unique_ptr<ASTConsumer>
ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
OS = CreateOutputFile(CI, InFile);
+
if (!OS)
return nullptr;
@@ -331,17 +412,17 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
- CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
- CI.getSourceManager(), *LCF, *API, CI.getPreprocessor()));
+ CI.getPreprocessor().addPPCallbacks(std::make_unique<APIMacroCallback>(
+ CI.getSourceManager(), *API, CI.getPreprocessor(), *LCF));
// Do not include location in anonymous decls.
PrintingPolicy Policy = CI.getASTContext().getPrintingPolicy();
Policy.AnonymousTagLocations = false;
CI.getASTContext().setPrintingPolicy(Policy);
- if (!CI.getFrontendOpts().ExtractAPIIgnoresFile.empty()) {
+ if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
llvm::handleAllErrors(
- APIIgnoresList::create(CI.getFrontendOpts().ExtractAPIIgnoresFile,
+ APIIgnoresList::create(CI.getFrontendOpts().ExtractAPIIgnoresFileList,
CI.getFileManager())
.moveInto(IgnoresList),
[&CI](const IgnoresFileNotFound &Err) {
@@ -412,23 +493,88 @@ bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
return true;
}
-void ExtractAPIAction::EndSourceFileAction() {
+void ExtractAPIAction::EndSourceFileAction() { ImplEndSourceFileAction(); }
+
+std::unique_ptr<ASTConsumer>
+WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+ if (!OtherConsumer)
+ return nullptr;
+
+ CreatedASTConsumer = true;
+
+ OS = CreateOutputFile(CI, InFile);
if (!OS)
- return;
+ return nullptr;
- // Setup a SymbolGraphSerializer to write out collected API information in
- // the Symbol Graph format.
- // FIXME: Make the kind of APISerializer configurable.
- SymbolGraphSerializer SGSerializer(*API, IgnoresList);
- SGSerializer.serialize(*OS);
- OS.reset();
+ auto ProductName = CI.getFrontendOpts().ProductName;
+
+ // Now that we have enough information about the language options and the
+ // target triple, let's create the APISet before anyone uses it.
+ API = std::make_unique<APISet>(
+ CI.getTarget().getTriple(),
+ CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), ProductName);
+
+ CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
+ CI.getSourceManager(), *API, CI.getPreprocessor()));
+
+ // Do not include location in anonymous decls.
+ PrintingPolicy Policy = CI.getASTContext().getPrintingPolicy();
+ Policy.AnonymousTagLocations = false;
+ CI.getASTContext().setPrintingPolicy(Policy);
+
+ if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
+ llvm::handleAllErrors(
+ APIIgnoresList::create(CI.getFrontendOpts().ExtractAPIIgnoresFileList,
+ CI.getFileManager())
+ .moveInto(IgnoresList),
+ [&CI](const IgnoresFileNotFound &Err) {
+ CI.getDiagnostics().Report(
+ diag::err_extract_api_ignores_file_not_found)
+ << Err.Path;
+ });
+ }
+
+ auto WrappingConsumer =
+ std::make_unique<WrappingExtractAPIConsumer>(CI.getASTContext(), *API);
+ std::vector<std::unique_ptr<ASTConsumer>> Consumers;
+ Consumers.push_back(std::move(OtherConsumer));
+ Consumers.push_back(std::move(WrappingConsumer));
+
+ return std::make_unique<MultiplexConsumer>(std::move(Consumers));
+}
+
+void WrappingExtractAPIAction::EndSourceFileAction() {
+ // Invoke wrapped action's method.
+ WrapperFrontendAction::EndSourceFileAction();
+
+ if (CreatedASTConsumer) {
+ ImplEndSourceFileAction();
+ }
}
std::unique_ptr<raw_pwrite_stream>
-ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
- std::unique_ptr<raw_pwrite_stream> OS =
- CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
- /*RemoveFileOnSignal=*/false);
+WrappingExtractAPIAction::CreateOutputFile(CompilerInstance &CI,
+ StringRef InFile) {
+ std::unique_ptr<raw_pwrite_stream> OS;
+ std::string OutputDir = CI.getFrontendOpts().SymbolGraphOutputDir;
+
+ // The symbol graphs need to be generated as a side effect of regular
+ // compilation so the output should be dumped in the directory provided with
+ // the command line option.
+ llvm::SmallString<128> OutFilePath(OutputDir);
+ auto Seperator = llvm::sys::path::get_separator();
+ auto Infilename = llvm::sys::path::filename(InFile);
+ OutFilePath.append({Seperator, Infilename});
+ llvm::sys::path::replace_extension(OutFilePath, "json");
+ // StringRef outputFilePathref = *OutFilePath;
+
+ // don't use the default output file
+ OS = CI.createOutputFile(/*OutputPath=*/OutFilePath, /*Binary=*/false,
+ /*RemoveFileOnSignal=*/true,
+ /*UseTemporary=*/true,
+ /*CreateMissingDirectories=*/true);
if (!OS)
return nullptr;
return OS;