[llvm-branch-commits] [clang] [DRAFT][SSAF] Add CLI option --ssaf-apply-source-pass for SourcePassAnalysis (PR #195746)
Ziqing Luo via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon May 4 16:46:08 PDT 2026
https://github.com/ziqingluo-90 updated https://github.com/llvm/llvm-project/pull/195746
>From ae5a3eed7eee53e507f6e4208c2072cbeac7141b Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziqing_luo at apple.com>
Date: Tue, 28 Apr 2026 18:48:13 -0700
Subject: [PATCH 1/2] [SSAF] Add CLI option --ssaf-apply-source-pass for
SourcePassAnalysis
The '--ssaf-apply-source-pass' option takes a list of
SourcePassAnalysis names. The option expects the user to provide a WPA
result using '--ssaf-load-wpa-result'.
Provided SourcePassAnalysis passes will be run by clang on each AST
with the WPA result.
---
.../clang/Basic/DiagnosticFrontendKinds.td | 10 +++
.../include/clang/Frontend/FrontendOptions.h | 6 ++
clang/include/clang/Options/Options.td | 14 +++
.../SourcePassAnalysisFrontendAction.h | 33 +++++++
.../ExecuteCompilerInvocation.cpp | 4 +
.../Frontend/CMakeLists.txt | 1 +
.../SourcePassAnalysisFrontendAction.cpp | 88 +++++++++++++++++++
.../Scalable/command-line-interface.cpp | 6 ++
clang/test/Analysis/Scalable/help.cpp | 6 +-
9 files changed, 167 insertions(+), 1 deletion(-)
create mode 100644 clang/include/clang/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.h
create mode 100644 clang/lib/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.cpp
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index f384a97b6825e..1647c869d2253 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -400,6 +400,16 @@ def warn_profile_data_misexpect : Warning<
BackendInfo, InGroup<MisExpect>;
} // end of instrumentation issue category
+def warn_ssaf_load_wpa_result_unknown_file_path_format :
+ Warning<"failed to parse the value of '--ssaf-load-wpa-result=%0' "
+ "the value must follow the '<path>.<format>' pattern">,
+ InGroup<ScalableStaticAnalysisFramework>, DefaultError;
+
+def warn_ssaf_load_wpa_result_unknown_file_data_format :
+ Warning<"unknown WPA file format '%0' "
+ "specified by '--ssaf-load-wpa-result=%1'">,
+ InGroup<ScalableStaticAnalysisFramework>, DefaultError;
+
def warn_ssaf_extract_tu_summary_file_unknown_output_format :
Warning<"unknown output summary file format '%0' "
"specified by '--ssaf-tu-summary-file=%1'">,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index f7f51bc37c98d..88ea5f4bf3bff 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -558,6 +558,12 @@ class FrontendOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned SSAFShowFormats : 1;
+ /// List of SSAF source-pass analysis names to apply.
+ std::vector<std::string> SSAFApplySourcePass;
+
+ /// The WPA result file to load, with file extension selecting the format.
+ std::string SSAFLoadWPAResult;
+
public:
FrontendOptions()
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c64ebba6f3dbf..610860de74b49 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -969,6 +969,20 @@ def _ssaf_list_formats :
Visibility<[ClangOption, CC1Option]>,
HelpText<"Display the list of available SSAF serialization formats">,
MarshallingInfoFlag<FrontendOpts<"SSAFShowFormats">>;
+def _ssaf_apply_source_pass :
+ CommaJoined<["--"], "ssaf-apply-source-pass=">,
+ MetaVarName<"<analysis-names>">,
+ Group<SSAF_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Comma-separated list of source-pass analysis names to apply">,
+ MarshallingInfoStringVector<FrontendOpts<"SSAFApplySourcePass">>;
+def _ssaf_load_wpa_result :
+ Joined<["--"], "ssaf-load-wpa-result=">,
+ MetaVarName<"<path>.<format>">,
+ Group<SSAF_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"The WPA result file to load. The extension selects which file format to use.">,
+ MarshallingInfoString<FrontendOpts<"SSAFLoadWPAResult">>;
def Xarch__
: JoinedAndSeparate<["-"], "Xarch_">,
Flags<[NoXarchOption]>,
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.h b/clang/include/clang/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.h
new file mode 100644
index 0000000000000..53d17576ca1e0
--- /dev/null
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.h
@@ -0,0 +1,33 @@
+//===- SourcePassAnalysisFrontendAction.h -----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_FRONTEND_SOURCEPASSANALYSISFRONTENDACTION_H
+#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_FRONTEND_SOURCEPASSANALYSISFRONTENDACTION_H
+
+#include "clang/Frontend/FrontendAction.h"
+#include <memory>
+
+namespace clang::ssaf {
+
+/// Wraps the existing \c FrontendAction and injects the source-pass analysis
+/// \c ASTConsumers into the pipeline after the ASTConsumers of the wrapped
+/// action.
+class SourcePassAnalysisFrontendAction final : public WrapperFrontendAction {
+public:
+ explicit SourcePassAnalysisFrontendAction(
+ std::unique_ptr<FrontendAction> WrappedAction);
+ ~SourcePassAnalysisFrontendAction();
+
+protected:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
+};
+
+} // namespace clang::ssaf
+
+#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_FRONTEND_SOURCEPASSANALYSISFRONTENDACTION_H
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index e4622496758ac..536ad2686a84a 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -23,6 +23,7 @@
#include "clang/FrontendTool/Utils.h"
#include "clang/Options/Options.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.h"
#include "clang/ScalableStaticAnalysisFramework/Frontend/TUSummaryExtractorFrontendAction.h"
#include "clang/ScalableStaticAnalysisFramework/SSAFForceLinker.h" // IWYU pragma: keep
#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h"
@@ -213,6 +214,9 @@ CreateFrontendAction(CompilerInstance &CI) {
Act = std::make_unique<ssaf::TUSummaryExtractorFrontendAction>(
std::move(Act));
}
+ if (!FEOpts.SSAFApplySourcePass.empty()) {
+ Act = std::make_unique<ssaf::SourcePassAnalysisFrontendAction>(std::move(Act));
+ }
return Act;
}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
index 3da1558810572..409e7841c3f3d 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangScalableStaticAnalysisFrameworkFrontend
+ SourcePassAnalysisFrontendAction.cpp
TUSummaryExtractorFrontendAction.cpp
LINK_LIBS
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.cpp b/clang/lib/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.cpp
new file mode 100644
index 0000000000000..173b2f7134f29
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.cpp
@@ -0,0 +1,88 @@
+//===- SourcePassAnalysisFrontendAction.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/ScalableStaticAnalysisFramework/Frontend/SourcePassAnalysisFrontendAction.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormatRegistry.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/SourcePassAnalysis/SourcePassAnalysisRegistry.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/WholeProgramAnalysis/WPASuite.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/IOSandbox.h"
+#include "llvm/Support/Path.h"
+#include <memory>
+
+using namespace clang;
+using namespace ssaf;
+
+SourcePassAnalysisFrontendAction::~SourcePassAnalysisFrontendAction() = default;
+
+SourcePassAnalysisFrontendAction::SourcePassAnalysisFrontendAction(
+ std::unique_ptr<FrontendAction> WrappedAction)
+ : WrapperFrontendAction(std::move(WrappedAction)) {}
+
+std::unique_ptr<ASTConsumer>
+SourcePassAnalysisFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ auto WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+ if (!WrappedConsumer)
+ return nullptr;
+
+ const FrontendOptions &Opts = CI.getFrontendOpts();
+
+ // Parse format from file extension.
+ StringRef File = Opts.SSAFLoadWPAResult;
+ StringRef Ext = llvm::sys::path::extension(File);
+
+ if (!Ext.consume_front(".") || File.empty()) {
+ CI.getDiagnostics().Report(
+ diag::warn_ssaf_load_wpa_result_unknown_file_path_format)
+ << File;
+ return WrappedConsumer;
+ }
+
+ if (!isFormatRegistered(Ext)) {
+ CI.getDiagnostics().Report(
+ diag::warn_ssaf_load_wpa_result_unknown_file_data_format)
+ << Ext << File;
+ return WrappedConsumer;
+ }
+
+ // Load WPA results.
+ auto Format = makeFormat(Ext);
+
+ // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
+ llvm::sys::sandbox::ScopedSetting Guard = llvm::sys::sandbox::scopedDisable();
+
+ CI.getCodeGenOpts().ClearASTBeforeBackend = false;
+
+ // Instantiate each requested source-pass analysis.
+ // FIXME: WPASuite is not copyable. For now, each analysis gets a fresh read.
+ // Consider shared ownership if multiple analyses need the same suite.
+ std::vector<std::unique_ptr<ASTConsumer>> Consumers;
+ Consumers.push_back(std::move(WrappedConsumer));
+
+ for (const auto &Name : Opts.SSAFApplySourcePass) {
+ auto SuiteOrErr = Format->readWPASuite(File);
+ if (!SuiteOrErr) {
+ llvm::report_fatal_error(SuiteOrErr.takeError());
+ continue;
+ }
+ auto AnalysisOrErr = SourcePassAnalysisRegistry::instantiate(
+ AnalysisName(Name), std::make_unique<WPASuite>(std::move(*SuiteOrErr)));
+ if (!AnalysisOrErr) {
+ llvm::report_fatal_error(AnalysisOrErr.takeError());
+ continue;
+ }
+ Consumers.push_back(std::move(*AnalysisOrErr));
+ }
+
+ return std::make_unique<MultiplexConsumer>(std::move(Consumers));
+}
diff --git a/clang/test/Analysis/Scalable/command-line-interface.cpp b/clang/test/Analysis/Scalable/command-line-interface.cpp
index a632f487f2bb7..ea215fe4cd4b5 100644
--- a/clang/test/Analysis/Scalable/command-line-interface.cpp
+++ b/clang/test/Analysis/Scalable/command-line-interface.cpp
@@ -20,3 +20,9 @@ void empty() {}
// NO-EXTRACTORS-ENABLED: error: must enable some summary extractors using the '--ssaf-extract-summaries=' option [-Wscalable-static-analysis-framework]
// NO-EXTRACTOR-WITH-NAME: error: no summary extractor was registered with name: extractor1 [-Wscalable-static-analysis-framework]
// NO-EXTRACTORS-WITH-NAME: error: no summary extractors were registered with name: extractor1, extractor2 [-Wscalable-static-analysis-framework]
+
+// RUN: not %clang_cc1 -fsyntax-only %s --ssaf-apply-source-pass=X --ssaf-load-wpa-result=foo.unknownfmt 2>&1 | %{filecheck}=UNKNOWN-WPA-INPUT-FORMAT
+// RUN: not %clang_cc1 -fsyntax-only %s --ssaf-apply-source-pass=SomeAnalysis 2>&1 | %{filecheck}=NO-WPA-FILE
+
+// UNKNOWN-WPA-INPUT-FORMAT: error: unknown WPA file format 'unknownfmt' specified by '--ssaf-load-wpa-result=foo.unknownfmt' [-Wscalable-static-analysis-framework]
+// NO-WPA-FILE: error: failed to parse the value of '--ssaf-load-wpa-result=' the value must follow the '<path>.<format>' pattern [-Wscalable-static-analysis-framework]
diff --git a/clang/test/Analysis/Scalable/help.cpp b/clang/test/Analysis/Scalable/help.cpp
index a2e72cd198af7..274ef923a6e84 100644
--- a/clang/test/Analysis/Scalable/help.cpp
+++ b/clang/test/Analysis/Scalable/help.cpp
@@ -3,10 +3,14 @@
// RUN: %clang --help 2>&1 | %{filecheck}=HELP
// RUN: %clang_cc1 --help 2>&1 | %{filecheck}=HELP
-// HELP: --ssaf-extract-summaries=<summary-names>
+// HELP: --ssaf-apply-source-pass=<analysis-names>
+// HELP-NEXT: Comma-separated list of source-pass analysis names to apply
+// HELP-NEXT: --ssaf-extract-summaries=<summary-names>
// HELP-NEXT: Comma-separated list of summary names to extract
// HELP-NEXT: --ssaf-list-extractors Display the list of available SSAF summary extractors
// HELP-NEXT: --ssaf-list-formats Display the list of available SSAF serialization formats
+// HELP-NEXT: --ssaf-load-wpa-result=<path>.<format>
+// HELP-NEXT: The WPA result file to load. The extension selects which file format to use.
// HELP-NEXT: --ssaf-tu-summary-file=<path>.<format>
// HELP-NEXT: The output file for the extracted summaries. The extension selects which file format to use.
>From dc924524e9e00169b6eadd46bf083227a1879925 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziqing_luo at apple.com>
Date: Mon, 4 May 2026 16:35:59 -0700
Subject: [PATCH 2/2] fix clang-format
---
clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 536ad2686a84a..9bfec61bfdcb1 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -215,7 +215,8 @@ CreateFrontendAction(CompilerInstance &CI) {
std::move(Act));
}
if (!FEOpts.SSAFApplySourcePass.empty()) {
- Act = std::make_unique<ssaf::SourcePassAnalysisFrontendAction>(std::move(Act));
+ Act = std::make_unique<ssaf::SourcePassAnalysisFrontendAction>(
+ std::move(Act));
}
return Act;
}
More information about the llvm-branch-commits
mailing list