diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-09-02 21:17:18 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-12-08 17:34:50 +0000 |
| commit | 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e (patch) | |
| tree | 62f873df87c7c675557a179e0c4c83fe9f3087bc /contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | |
| parent | cf037972ea8863e2bab7461d77345367d2c1e054 (diff) | |
| parent | 7fa27ce4a07f19b07799a767fc29416f3b625afb (diff) | |
Diffstat (limited to 'contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 194 |
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; |
