https://github.com/steakhal created 
https://github.com/llvm/llvm-project/pull/205351

This option allows including local entities in summaries. This means that 
ContributorFinder can optionally include block-scope (function-local) variables.
Parameters are intentionally skipped: they are exposed via their parent 
function's USR + a parameter-index suffix in getEntityName, so registering them 
as independent contributors would be redundant.

Part §2 of rdar://179151023

From 8d1f3e75f067e3a312a7689a43a1372411f6b4e6 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Tue, 12 May 2026 18:25:53 -0700
Subject: [PATCH] [clang][ssaf] Add --ssaf-include-local-entities flag
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This option allows including local entities in summaries.
This means that ContributorFinder can optionally include block-scope
(function-local) variables.
Parameters are intentionally skipped: they are exposed via their parent 
function's
USR + a parameter-index suffix in getEntityName, so registering them as
independent contributors would be redundant.

Part §2 of rdar://179151023

Co-Authored-By: Jan Korous <[email protected]>
Co-Authored-By: Claude Opus 4.7 <[email protected]>
---
 clang/include/clang/Frontend/SSAFOptions.h    |  7 +++++
 clang/include/clang/Options/Options.td        |  8 ++++++
 clang/lib/Driver/ToolChains/Clang.cpp         |  1 +
 .../PointerFlow/PointerFlowExtractor.cpp      |  2 +-
 .../Analyses/SSAFAnalysesCommon.cpp           | 27 ++++++++++++++++---
 .../Analyses/SSAFAnalysesCommon.h             | 11 +++++++-
 .../UnsafeBufferUsageExtractor.cpp            |  2 +-
 .../Scalable/command-line-interface.cpp       | 13 +++++++++
 clang/test/Analysis/Scalable/help.cpp         |  2 ++
 9 files changed, 66 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Frontend/SSAFOptions.h 
b/clang/include/clang/Frontend/SSAFOptions.h
index 738262cc4a713..f760d51ab5414 100644
--- a/clang/include/clang/Frontend/SSAFOptions.h
+++ b/clang/include/clang/Frontend/SSAFOptions.h
@@ -41,9 +41,16 @@ class SSAFOptions {
   LLVM_PREFERRED_TYPE(bool)
   unsigned ShowFormats : 1;
 
+  /// Include block-scope (function-local) declarations in extracted SSAF
+  /// summaries. Defaults to false to preserve the original behavior.
+  /// Controlled by: --ssaf-include-local-entities
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned IncludeLocalEntities : 1;
+
   SSAFOptions() {
     ShowExtractors = false;
     ShowFormats = false;
+    IncludeLocalEntities = false;
   };
 };
 
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 4fc9f4d4c3472..f4a7fb8586e99 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -981,6 +981,14 @@ def _ssaf_compilation_unit_id :
     "produced SSAF TU summary. Required when '--ssaf-tu-summary-file=' is "
     "set.">,
   MarshallingInfoString<SSAFOpts<"CompilationUnitId">>;
+def _ssaf_include_local_entities :
+  Flag<["--"], "ssaf-include-local-entities">,
+  Group<SSAF_Group>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<
+    "Include block-scope (function-local) declarations in extracted SSAF "
+    "summaries. By default they are omitted.">,
+  MarshallingInfoFlag<SSAFOpts<"IncludeLocalEntities">>;
 def Xarch__
     : JoinedAndSeparate<["-"], "Xarch_">,
       Flags<[NoXarchOption]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 418d540895681..3333698c87e36 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7944,6 +7944,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
   Args.AddLastArg(CmdArgs, options::OPT__ssaf_extract_summaries);
   Args.AddLastArg(CmdArgs, options::OPT__ssaf_tu_summary_file);
   Args.AddLastArg(CmdArgs, options::OPT__ssaf_compilation_unit_id);
+  Args.AddLastArg(CmdArgs, options::OPT__ssaf_include_local_entities);
 
   // Handle serialized diagnostics.
   if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
index ef5932c52a6c3..aee1387228ba0 100644
--- 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
@@ -333,7 +333,7 @@ class PointerFlowTUSummaryExtractor : public 
TUSummaryExtractor {
   void HandleTranslationUnit(ASTContext &Ctx) override {
     std::vector<const NamedDecl *> Contributors;
 
-    findContributors(Ctx, Contributors);
+    findContributors(Ctx, getOptions(), Contributors);
     for (auto *CD : Contributors) {
       // Templates are skipped, but their instantiations are handled. The idea
       // is that we can conclude facts about a template through all of its
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
index 660bc424fb32f..65087b2cf1227 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
@@ -12,9 +12,11 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/Frontend/SSAFOptions.h"
 #include <set>
 
 using namespace clang;
+using namespace ssaf;
 
 std::string ssaf::describeJSONValue(const llvm::json::Value &V) {
   return llvm::formatv("{0:2}", V).str();
@@ -33,8 +35,9 @@ namespace {
 class ContributorFinder : public DynamicRecursiveASTVisitor {
 public:
   std::set<const NamedDecl *> Contributors;
+  const SSAFOptions &Opts;
 
-  ContributorFinder() {
+  ContributorFinder(const SSAFOptions &Opts) : Opts(Opts) {
     ShouldVisitTemplateInstantiations = true;
     ShouldVisitImplicitCode = false;
   }
@@ -53,7 +56,23 @@ class ContributorFinder : public DynamicRecursiveASTVisitor {
     DeclContext *DC = D->getDeclContext();
 
     // Collects Decl for global variables or static data members:
-    if (DC->isFileContext() || D->isStaticDataMember())
+    if (DC->isFileContext() || D->isStaticDataMember()) {
+      Contributors.insert(D);
+      return true;
+    }
+
+    // Optionally include block-scope (function-local) variables. Parameters
+    // are intentionally skipped: they are exposed via their parent function's
+    // USR + a parameter-index suffix in getEntityName, so registering them as
+    // independent contributors would be redundant.
+    //
+    // FIXME: clang::index::generateUSRForDecl can produce non-unique or empty
+    // USRs for some local declaration shapes (e.g., locals of certain template
+    // instantiations). The current addEntity path returns std::nullopt when
+    // that happens and downstream extractors skip gracefully, so this is
+    // tolerated for now.
+    if (Opts.IncludeLocalEntities && !D->isImplicit() && !isa<ParmVarDecl>(D) 
&&
+        DC->isFunctionOrMethod())
       Contributors.insert(D);
     return true;
   }
@@ -124,9 +143,9 @@ class ContributorFactFinder : public 
DynamicRecursiveASTVisitor {
 };
 } // namespace
 
-void ssaf::findContributors(ASTContext &Ctx,
+void ssaf::findContributors(ASTContext &Ctx, const SSAFOptions &Options,
                             std::vector<const NamedDecl *> &Contributors) {
-  ContributorFinder Finder;
+  ContributorFinder Finder{Options};
   Finder.TraverseAST(Ctx);
   Contributors.insert(Contributors.end(), Finder.Contributors.begin(),
                       Finder.Contributors.end());
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
index 38c37e7103b73..a2b99484af3c4 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
@@ -21,6 +21,8 @@
 #include "llvm/Support/raw_ostream.h"
 
 namespace clang::ssaf {
+class SSAFOptions;
+
 ///\return a short descriptions of a json::Value
 std::string describeJSONValue(const llvm::json::Value &V);
 ///\return a short descriptions of a json::Array
@@ -67,7 +69,14 @@ inline void logWarningFromError(llvm::Error Err) {
 }
 
 /// Find all contributors in an AST.
-void findContributors(ASTContext &Ctx,
+///
+/// \p Options controls which declarations qualify as contributors. By default
+/// the visitor preserves the original SSAF behavior of skipping block-scope
+/// (function-local) variable declarations; setting
+/// \c Options.IncludeLocalEntities to \c true also collects local variables
+/// (excluding function parameters, which are addressed via their parent
+/// function's USR).
+void findContributors(ASTContext &Ctx, const SSAFOptions &Options,
                       std::vector<const NamedDecl *> &Contributors);
 
 /// Perform "MatchAction" on each Stmt and Decl belonging to the `Contributor`.
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
index f4067e5f315ff..ae0c2855008a0 100644
--- 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
@@ -72,7 +72,7 @@ void 
clang::ssaf::UnsafeBufferUsageTUSummaryExtractor::HandleTranslationUnit(
     ASTContext &Ctx) {
   std::vector<const NamedDecl *> Contributors;
 
-  findContributors(Ctx, Contributors);
+  findContributors(Ctx, getOptions(), Contributors);
   for (auto *CD : Contributors) {
     // Templates are skipped, but their instantiations are handled. The idea
     // is that we can conclude facts about a template through all of its
diff --git a/clang/test/Analysis/Scalable/command-line-interface.cpp 
b/clang/test/Analysis/Scalable/command-line-interface.cpp
index fc01051a4a8f0..0af37cb926ae3 100644
--- a/clang/test/Analysis/Scalable/command-line-interface.cpp
+++ b/clang/test/Analysis/Scalable/command-line-interface.cpp
@@ -13,6 +13,19 @@
 // RUN: not %clang     -fsyntax-only %s --ssaf-tu-summary-file=%t.ssaf.json 
--ssaf-compilation-unit-id=test-cu 
--ssaf-extract-summaries=extractor1,extractor2 2>&1 | 
%{filecheck}=NO-EXTRACTORS-WITH-NAME
 // RUN: not %clang_cc1 -fsyntax-only %s --ssaf-tu-summary-file=%t.ssaf.json 
--ssaf-compilation-unit-id=test-cu 
--ssaf-extract-summaries=extractor1,extractor2 2>&1 | 
%{filecheck}=NO-EXTRACTORS-WITH-NAME
 
+// Verify --ssaf-include-local-entities is accepted alongside summary 
extraction
+// in both the driver and CC1, and that without --ssaf-tu-summary-file= the
+// flag is silently ignored (same shape as --ssaf-list-extractors).
+// RUN: rm -rf %t.localents && mkdir %t.localents
+// RUN: %clang     -fsyntax-only %s --ssaf-include-local-entities
+// RUN: %clang_cc1 -fsyntax-only %s --ssaf-include-local-entities
+// RUN: %clang     -fsyntax-only %s 
--ssaf-tu-summary-file=%t.localents/a.ssaf.json 
--ssaf-compilation-unit-id=test-cu --ssaf-extract-summaries=CallGraph 
--ssaf-include-local-entities
+// RUN: %clang_cc1 -fsyntax-only %s 
--ssaf-tu-summary-file=%t.localents/b.ssaf.json 
--ssaf-compilation-unit-id=test-cu --ssaf-extract-summaries=CallGraph 
--ssaf-include-local-entities
+
+// Verify the driver forwards the flag to CC1.
+// RUN: %clang -### -fsyntax-only %s --ssaf-include-local-entities 
--ssaf-tu-summary-file=%t.localents/c.ssaf.json 
--ssaf-compilation-unit-id=test-cu --ssaf-extract-summaries=CallGraph 2>&1 | 
FileCheck %s --check-prefix=DRIVER-FORWARDS-FLAG
+// DRIVER-FORWARDS-FLAG: "-cc1"{{.+}}"--ssaf-include-local-entities"
+
 void empty() {}
 
 // NOT-MATCHING-THE-PATTERN: error: failed to parse the value of 
'--ssaf-tu-summary-file=foobar' 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 15d6d109360d8..3feae2dfaa456 100644
--- a/clang/test/Analysis/Scalable/help.cpp
+++ b/clang/test/Analysis/Scalable/help.cpp
@@ -7,6 +7,8 @@
 // HELP-NEXT:    Stable identifier used as the CompilationUnit namespace name 
of every produced SSAF TU summary. Required when '--ssaf-tu-summary-file=' is 
set.
 // HELP-NEXT:  --ssaf-extract-summaries=<summary-names>
 // HELP-NEXT:    Comma-separated list of summary names to extract
+// HELP-NEXT:  --ssaf-include-local-entities
+// HELP-NEXT:    Include block-scope (function-local) declarations in 
extracted SSAF summaries. By default they are omitted.
 // 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-tu-summary-file=<path>.<format>

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to