[clang] [clang][ssaf] Add --ssaf-extract-summaries= and --ssaf-tu-summary-file= options (PR #184421)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 7 01:52:19 PST 2026
================
@@ -0,0 +1,181 @@
+//===- TUSummaryExtractorFrontendAction.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Scalable/Frontend/TUSummaryExtractorFrontendAction.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Analysis/Scalable/Serialization/SerializationFormatRegistry.h"
+#include "clang/Analysis/Scalable/TUSummary/ExtractorRegistry.h"
+#include "clang/Analysis/Scalable/TUSummary/TUSummary.h"
+#include "clang/Analysis/Scalable/TUSummary/TUSummaryBuilder.h"
+#include "clang/Analysis/Scalable/TUSummary/TUSummaryExtractor.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Path.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+using namespace clang;
+using namespace ssaf;
+
+static std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
+parseOutputFileFormatAndPathOrReportError(DiagnosticsEngine &Diags,
+ StringRef SSAFTUSummaryFile) {
+
+ StringRef Ext = llvm::sys::path::extension(SSAFTUSummaryFile);
+ StringRef FilePath = SSAFTUSummaryFile.drop_back(Ext.size());
+
+ if (!Ext.consume_front(".") || FilePath.empty()) {
+ Diags.Report(diag::warn__ssaf_extract_tu_summary_file_unknown_format)
+ << SSAFTUSummaryFile;
+ return std::nullopt;
+ }
+
+ if (!isFormatRegistered(Ext)) {
+ Diags.Report(diag::warn__ssaf_extract_tu_summary_file_unknown_output_format)
+ << Ext << SSAFTUSummaryFile;
+ return std::nullopt;
+ }
+
+ return std::pair{Ext, FilePath};
+}
+
+/// Return \c true if reported unrecognized extractors.
+static bool
+reportUnrecognizedExtractorNames(DiagnosticsEngine &Diags,
+ ArrayRef<std::string> SSAFExtractSummaries) {
+ if (SSAFExtractSummaries.empty()) {
+ Diags.Report(diag::warn__ssaf_must_enable_summary_extractors);
+ return true;
+ }
+
+ std::vector<StringRef> UnrecognizedExtractorNames;
+ for (StringRef Name : SSAFExtractSummaries)
+ if (!isTUSummaryExtractorRegistered(Name))
+ UnrecognizedExtractorNames.push_back(Name);
+
+ if (!UnrecognizedExtractorNames.empty()) {
+ Diags.Report(diag::warn__ssaf_extract_summary_unknown_extractor_name)
+ << UnrecognizedExtractorNames.size()
+ << llvm::join(UnrecognizedExtractorNames, ", ");
+ return true;
+ }
+
+ return false;
+}
+
+static std::vector<std::unique_ptr<ASTConsumer>>
+makeTUSummaryExtractors(TUSummaryBuilder &Builder,
+ ArrayRef<std::string> SSAFExtractSummaries) {
+ std::vector<std::unique_ptr<ASTConsumer>> Extractors;
+ Extractors.reserve(SSAFExtractSummaries.size());
+ for (StringRef Name : SSAFExtractSummaries) {
+ assert(isTUSummaryExtractorRegistered(Name));
+ Extractors.push_back(makeTUSummaryExtractor(Name, Builder));
+ }
+ return Extractors;
+}
+
+namespace {
+
+/// Drives all extractor \c ASTConsumers and serializes the completed
+/// \c TUSummary.
+///
+/// Derives from \c MultiplexConsumer so every \c ASTConsumer virtual method is
+/// automatically forwarded to each extractor.
+class TUSummaryRunner final : public MultiplexConsumer {
+public:
+ static std::unique_ptr<TUSummaryRunner> create(CompilerInstance &CI,
+ StringRef InFile);
+
+private:
+ TUSummaryRunner(StringRef InFile, std::unique_ptr<SerializationFormat> Format,
+ const FrontendOptions &Opts);
+
+ void HandleTranslationUnit(ASTContext &Ctx) override;
+
+ TUSummary Summary;
+ TUSummaryBuilder Builder = TUSummaryBuilder(Summary);
+ std::unique_ptr<SerializationFormat> Format;
+ const FrontendOptions &Opts;
+};
+} // namespace
+
+std::unique_ptr<TUSummaryRunner> TUSummaryRunner::create(CompilerInstance &CI,
+ StringRef InFile) {
+ const FrontendOptions &Opts = CI.getFrontendOpts();
+ DiagnosticsEngine &Diags = CI.getDiagnostics();
+
+ auto MaybePair =
+ parseOutputFileFormatAndPathOrReportError(Diags, Opts.SSAFTUSummaryFile);
+ if (!MaybePair.has_value())
+ return nullptr;
+ auto [FormatName, OutputPath] = MaybePair.value();
+
+ if (reportUnrecognizedExtractorNames(Diags, Opts.SSAFExtractSummaries))
+ return nullptr;
+
+ return std::unique_ptr<TUSummaryRunner>{
+ new TUSummaryRunner{InFile, makeFormat(FormatName), Opts}};
+}
+
+TUSummaryRunner::TUSummaryRunner(StringRef InFile,
+ std::unique_ptr<SerializationFormat> Format,
+ const FrontendOptions &Opts)
+ : MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>>{}),
+ Summary(BuildNamespace(BuildNamespaceKind::CompilationUnit, InFile)),
+ Format(std::move(Format)), Opts(Opts) {
+ assert(this->Format);
+
+ // Now the Summary and the builders are constructed, we can also construct the
+ // extractors.
+ auto Extractors = makeTUSummaryExtractors(Builder, Opts.SSAFExtractSummaries);
+ assert(!Extractors.empty());
+
+ // We must initialize the Consumers here because our extractors need a
+ // Builder that holds a reference to the TUSummary, which would be only
+ // initialized after the MultiplexConsumer ctor. This is the only way we can
+ // avoid the use of the TUSummary before it starts its lifetime.
+ MultiplexConsumer::Consumers = std::move(Extractors);
+}
+
+void TUSummaryRunner::HandleTranslationUnit(ASTContext &Ctx) {
+ // First, invoke the Summary Extractors.
+ MultiplexConsumer::HandleTranslationUnit(Ctx);
+
+ // Then serialize the result.
+ if (auto Err = Format->writeTUSummary(Summary, Opts.SSAFTUSummaryFile)) {
+ Ctx.getDiagnostics().Report(diag::warn__ssaf_write_tu_summary_failed)
+ << Opts.SSAFTUSummaryFile << llvm::toString(std::move(Err));
+ }
+}
+
+TUSummaryExtractorFrontendAction::~TUSummaryExtractorFrontendAction() = default;
+
+TUSummaryExtractorFrontendAction::TUSummaryExtractorFrontendAction(
+ std::unique_ptr<FrontendAction> WrappedAction)
+ : WrapperFrontendAction(std::move(WrappedAction)) {}
+
+std::unique_ptr<ASTConsumer>
+TUSummaryExtractorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ auto WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+ if (!WrappedConsumer)
+ return nullptr;
+
+ if (auto Runner = TUSummaryRunner::create(CI, InFile)) {
----------------
steakhal wrote:
Exactly. But they must be declared as warnings to be downgradable to warnings now that they would default to errors. The tests demonstrate every possible uses of this.
https://github.com/llvm/llvm-project/pull/184421
More information about the cfe-commits
mailing list