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
