[clang] [Draft] Summary Based Analysis Prototype (PR #144224)

via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 14 13:07:52 PDT 2025


https://github.com/isuckatcs updated https://github.com/llvm/llvm-project/pull/144224

>From 7fba0addb97f9195eb307882254207f9b58072f2 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 22 May 2025 22:43:35 +0200
Subject: [PATCH 01/28] [clang][Driver] Add option to emit summaries

---
 clang/include/clang/Driver/Options.td         | 13 ++++++++++
 .../include/clang/Frontend/FrontendOptions.h  |  3 +++
 clang/lib/Driver/ToolChains/Clang.cpp         | 24 +++++++++++++++++++
 clang/lib/Frontend/FrontendAction.cpp         |  6 +++++
 4 files changed, 46 insertions(+)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 22261621df092..f0c7b277e68e2 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5941,6 +5941,15 @@ def save_temps : Flag<["-", "--"], "save-temps">, Flags<[NoXarchOption]>,
   Visibility<[ClangOption, FlangOption, FC1Option]>,
   Alias<save_temps_EQ>, AliasArgs<["cwd"]>,
   HelpText<"Alias for --save-temps=cwd">;
+def emit_summaries_EQ : Joined<["-", "--"], "emit-summaries=">, Flags<[NoXarchOption]>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Save summaries about the different functions. <arg> can be set to 'cwd' for "
+  "current working directory, or 'obj' which will save temporary files in the "
+  "same directory as the final output file">;
+def emit_summaries : Flag<["-", "--"], "emit-summaries">, Flags<[NoXarchOption]>,
+  Visibility<[ClangOption]>,
+  Alias<emit_summaries_EQ>, AliasArgs<["cwd"]>,
+  HelpText<"Alias for --emit-summaries=cwd">;
 def save_stats_EQ : Joined<["-", "--"], "save-stats=">, Flags<[NoXarchOption]>,
   HelpText<"Save llvm statistics.">;
 def save_stats : Flag<["-", "--"], "save-stats">, Flags<[NoXarchOption]>,
@@ -8148,6 +8157,10 @@ defm emit_llvm_uselists : BoolOption<"", "emit-llvm-uselists",
   NegFlag<SetFalse, [], [ClangOption], "Don't preserve">,
   BothFlags<[], [ClangOption], " order of LLVM use-lists when serializing">>;
 
+def summary_file : Joined<["-"], "summary-file=">,
+  HelpText<"Filename to write summaries about function definitions to">,
+  MarshallingInfoString<FrontendOpts<"SummaryFile">>;
+
 def print_stats : Flag<["-"], "print-stats">,
   HelpText<"Print performance metrics and statistics">,
   MarshallingInfoFlag<FrontendOpts<"ShowStats">>;
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index c919a53ae089e..af2451c1bde8e 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -534,6 +534,9 @@ class FrontendOptions {
   /// minimization hints.
   std::string DumpMinimizationHintsPath;
 
+  /// Filename to write summaries about function definitions to.
+  std::string SummaryFile;
+
 public:
   FrontendOptions()
       : DisableFree(false), RelocatablePCH(false), ShowHelp(false),
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 2fb6cf8ea2bdc..676a4e34ddb27 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5470,6 +5470,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (Args.getLastArg(options::OPT_save_temps_EQ))
     Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
 
+  // FIXME: This needs to be cleaned up and needs proper error handling as well.
+  if (const Arg *A = Args.getLastArg(options::OPT_emit_summaries_EQ)) {
+    llvm::SmallString<10> input;
+    for (const auto &II : Inputs) {
+      if (!II.isFilename())
+        continue;
+
+      input = II.getFilename();
+      break;
+    }
+
+    if (!input.empty()) {
+      if (A->containsValue("cwd")) {
+        llvm::SmallString<10> filename = llvm::sys::path::filename(input);
+        llvm::sys::path::replace_extension(filename, "json");
+
+        CmdArgs.push_back(
+            Args.MakeArgString(Twine("-summary-file=") + filename));
+      } else if (A->containsValue("obj")) {
+        // FIXME: implement
+      }
+    }
+  }
+
   auto *MemProfArg = Args.getLastArg(options::OPT_fmemory_profile,
                                      options::OPT_fmemory_profile_EQ,
                                      options::OPT_fno_memory_profile);
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 54a2e3eb297f5..868a1f70abd43 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -1253,6 +1253,12 @@ void FrontendAction::EndSourceFile() {
   // Finalize the action.
   EndSourceFileAction();
 
+  if (CI.hasSema() && !CI.getFrontendOpts().SummaryFile.empty()) {
+    std::error_code EC;
+    llvm::raw_fd_ostream(CI.getFrontendOpts().SummaryFile, EC,
+                         llvm::sys::fs::CD_CreateAlways);
+  }
+
   // Sema references the ast consumer, so reset sema first.
   //
   // FIXME: There is more per-file stuff we could just drop here?

>From 3d7d23ad7815ef4527f000651f4321348b200873 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 7 Jun 2025 21:38:36 +0200
Subject: [PATCH 02/28] [clang][Summary] add the summarizer skeleton

---
 .../include/clang/Frontend/CompilerInstance.h | 21 ++++++++++++++++++-
 clang/include/clang/Sema/Sema.h               |  6 +++++-
 clang/include/clang/Sema/SemaSummarizer.h     | 19 +++++++++++++++++
 clang/include/clang/Sema/SummaryConsumer.h    |  8 +++++++
 clang/lib/Frontend/ChainedIncludesSource.cpp  |  2 +-
 clang/lib/Frontend/CompilerInstance.cpp       | 11 ++++++++--
 clang/lib/Frontend/FrontendAction.cpp         | 10 ++++++++-
 clang/lib/Frontend/FrontendActions.cpp        |  2 +-
 clang/lib/Sema/CMakeLists.txt                 |  1 +
 clang/lib/Sema/Sema.cpp                       |  7 ++++++-
 clang/lib/Sema/SemaDecl.cpp                   |  4 ++++
 clang/lib/Sema/SemaSummarizer.cpp             |  8 +++++++
 clang/lib/Testing/TestAST.cpp                 |  2 +-
 clang/unittests/CodeGen/TestCompiler.h        |  2 +-
 .../unittests/Frontend/CodeGenActionTest.cpp  |  2 +-
 .../unittests/Sema/ExternalSemaSourceTest.cpp |  2 +-
 clang/unittests/Sema/SemaLookupTest.cpp       |  2 +-
 17 files changed, 96 insertions(+), 13 deletions(-)
 create mode 100644 clang/include/clang/Sema/SemaSummarizer.h
 create mode 100644 clang/include/clang/Sema/SummaryConsumer.h
 create mode 100644 clang/lib/Sema/SemaSummarizer.cpp

diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index 5f25a932c5052..f296e6d042a54 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -48,6 +48,7 @@ class ModuleFile;
 }
 
 class CodeCompleteConsumer;
+class SummaryConsumer;
 class DiagnosticsEngine;
 class DiagnosticConsumer;
 class FileManager;
@@ -121,6 +122,9 @@ class CompilerInstance : public ModuleLoader {
   /// The code completion consumer.
   std::unique_ptr<CodeCompleteConsumer> CompletionConsumer;
 
+  /// The summary consumer.
+  std::unique_ptr<SummaryConsumer> TheSummaryConsumer;
+
   /// The semantic analysis object.
   std::unique_ptr<Sema> TheSema;
 
@@ -607,6 +611,18 @@ class CompilerInstance : public ModuleLoader {
     return *CompletionConsumer;
   }
 
+  /// @}
+  /// @name Summary
+  /// @{
+
+  bool hasSummaryConsumer() const { return (bool)TheSummaryConsumer; }
+
+  SummaryConsumer &getSummaryConsumer() const {
+    assert(TheSummaryConsumer &&
+           "Compiler instance has no code summary consumer!");
+    return *TheSummaryConsumer;
+  }
+
   /// setCodeCompletionConsumer - Replace the current code completion consumer;
   /// the compiler instance takes ownership of \p Value.
   void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
@@ -736,9 +752,12 @@ class CompilerInstance : public ModuleLoader {
       Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column,
       const CodeCompleteOptions &Opts, raw_ostream &OS);
 
+  void createSummaryConsumer();
+
   /// Create the Sema object to be used for parsing.
   void createSema(TranslationUnitKind TUKind,
-                  CodeCompleteConsumer *CompletionConsumer);
+                  CodeCompleteConsumer *CompletionConsumer,
+                  SummaryConsumer *SummaryConsumer);
 
   /// Create the frontend timer and replace any existing one with it.
   void createFrontendTimer();
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fe93df94438cb..9cb2158ab4ff1 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -125,6 +125,7 @@ class CXXBasePath;
 class CXXBasePaths;
 class CXXFieldCollector;
 class CodeCompleteConsumer;
+class SummaryConsumer;
 enum class ComparisonCategoryType : unsigned char;
 class ConstraintSatisfaction;
 class DarwinSDKInfo;
@@ -159,6 +160,7 @@ class SemaARM;
 class SemaAVR;
 class SemaBPF;
 class SemaCodeCompletion;
+class SemaSummarizer;
 class SemaCUDA;
 class SemaDirectX;
 class SemaHLSL;
@@ -883,7 +885,8 @@ class Sema final : public SemaBase {
 public:
   Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
        TranslationUnitKind TUKind = TU_Complete,
-       CodeCompleteConsumer *CompletionConsumer = nullptr);
+       CodeCompleteConsumer *CompletionConsumer = nullptr,
+       SummaryConsumer *SummaryConsumer = nullptr);
   ~Sema();
 
   /// Perform initialization that occurs after the parser has been
@@ -1564,6 +1567,7 @@ class Sema final : public SemaBase {
   std::unique_ptr<SemaAVR> AVRPtr;
   std::unique_ptr<SemaBPF> BPFPtr;
   std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
+  std::unique_ptr<SemaSummarizer> SummarizerPtr;
   std::unique_ptr<SemaCUDA> CUDAPtr;
   std::unique_ptr<SemaDirectX> DirectXPtr;
   std::unique_ptr<SemaHLSL> HLSLPtr;
diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
new file mode 100644
index 0000000000000..3661e443bb2de
--- /dev/null
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -0,0 +1,19 @@
+#ifndef LLVM_CLANG_SEMA_SEMASUMMARIZER_H
+#define LLVM_CLANG_SEMA_SEMASUMMARIZER_H
+
+#include "clang/Sema/SemaBase.h"
+#include "clang/Sema/SummaryConsumer.h"
+
+namespace clang {
+class SemaSummarizer : public SemaBase {
+public:
+  SemaSummarizer(Sema &S, SummaryConsumer *SummaryConsumer)
+      : SemaBase(S), SummaryConsumer(SummaryConsumer) {}
+
+  SummaryConsumer *SummaryConsumer;
+
+  void SummarizeFunctionBody(FunctionDecl *FD) const;
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMASUMMARIZE_H
diff --git a/clang/include/clang/Sema/SummaryConsumer.h b/clang/include/clang/Sema/SummaryConsumer.h
new file mode 100644
index 0000000000000..8aa2713b46c65
--- /dev/null
+++ b/clang/include/clang/Sema/SummaryConsumer.h
@@ -0,0 +1,8 @@
+#ifndef LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
+#define LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
+
+namespace clang {
+class SummaryConsumer {};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp
index 95b0ed248d545..437f5387375f7 100644
--- a/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -142,7 +142,7 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
     Clang->getASTContext().setASTMutationListener(
                                             consumer->GetASTMutationListener());
     Clang->setASTConsumer(std::move(consumer));
-    Clang->createSema(TU_Prefix, nullptr);
+    Clang->createSema(TU_Prefix, nullptr, nullptr);
 
     if (firstInclude) {
       Preprocessor &PP = Clang->getPreprocessor();
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 503d36467653e..917a187f49fb5 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -37,6 +37,7 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/ParsedAttr.h"
 #include "clang/Sema/Sema.h"
+#include "clang/Sema/SummaryConsumer.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/GlobalModuleIndex.h"
 #include "clang/Serialization/InMemoryModuleCache.h"
@@ -741,10 +742,16 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
   return new PrintingCodeCompleteConsumer(Opts, OS);
 }
 
+void CompilerInstance::createSummaryConsumer() {
+  TheSummaryConsumer.reset(
+      getFrontendOpts().SummaryFile.empty() ? nullptr : new SummaryConsumer());
+}
+
 void CompilerInstance::createSema(TranslationUnitKind TUKind,
-                                  CodeCompleteConsumer *CompletionConsumer) {
+                                  CodeCompleteConsumer *CompletionConsumer,
+                                  SummaryConsumer *SummaryConsumer) {
   TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
-                         TUKind, CompletionConsumer));
+                         TUKind, CompletionConsumer, SummaryConsumer));
 
   // Set up API notes.
   TheSema->APINotes.setSwiftVersion(getAPINotesOpts().SwiftVersion);
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 868a1f70abd43..aeeab901b9ed7 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -1339,8 +1339,16 @@ void ASTFrontendAction::ExecuteAction() {
   if (CI.hasCodeCompletionConsumer())
     CompletionConsumer = &CI.getCodeCompletionConsumer();
 
+  CI.createSummaryConsumer();
+
+  // Use a code completion consumer?
+  SummaryConsumer *SummaryConsumer = nullptr;
+  if (CI.hasSummaryConsumer())
+    SummaryConsumer = &CI.getSummaryConsumer();
+
   if (!CI.hasSema())
-    CI.createSema(getTranslationUnitKind(), CompletionConsumer);
+    CI.createSema(getTranslationUnitKind(), CompletionConsumer,
+                  SummaryConsumer);
 
   ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
            CI.getFrontendOpts().SkipFunctionBodies);
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 8c75e1a46da54..49f1420c75047 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -52,7 +52,7 @@ void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) {
 
   if (!CI.hasSema())
     CI.createSema(Action.getTranslationUnitKind(),
-                  GetCodeCompletionConsumer(CI));
+                  GetCodeCompletionConsumer(CI), nullptr);
 }
 } // namespace
 
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 4b87004e4b8ea..5237f20201fde 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -85,6 +85,7 @@ add_clang_library(clangSema
   SemaStmt.cpp
   SemaStmtAsm.cpp
   SemaStmtAttr.cpp
+  SemaSummarizer.cpp
   SemaSPIRV.cpp
   SemaSYCL.cpp
   SemaSwift.cpp
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 1901d19b14dfc..2410d513c299e 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -64,6 +64,7 @@
 #include "clang/Sema/SemaRISCV.h"
 #include "clang/Sema/SemaSPIRV.h"
 #include "clang/Sema/SemaSYCL.h"
+#include "clang/Sema/SemaSummarizer.h"
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaSystemZ.h"
 #include "clang/Sema/SemaWasm.h"
@@ -248,7 +249,8 @@ const unsigned Sema::MaxAlignmentExponent;
 const uint64_t Sema::MaximumAlignment;
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
-           TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
+           TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter,
+           SummaryConsumer *SummaryConsumer)
     : SemaBase(*this), CollectStats(false), TUKind(TUKind),
       CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
       Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
@@ -263,6 +265,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       BPFPtr(std::make_unique<SemaBPF>(*this)),
       CodeCompletionPtr(
           std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
+      SummarizerPtr(SummaryConsumer ? std::make_unique<SemaSummarizer>(
+                                          *this, SummaryConsumer)
+                                    : nullptr),
       CUDAPtr(std::make_unique<SemaCUDA>(*this)),
       DirectXPtr(std::make_unique<SemaDirectX>(*this)),
       HLSLPtr(std::make_unique<SemaHLSL>(*this)),
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 814f81cb64cae..bb80fd2a46f58 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -55,6 +55,7 @@
 #include "clang/Sema/SemaPPC.h"
 #include "clang/Sema/SemaRISCV.h"
 #include "clang/Sema/SemaSYCL.h"
+#include "clang/Sema/SemaSummarizer.h"
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaWasm.h"
 #include "clang/Sema/Template.h"
@@ -16694,6 +16695,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
   if (FD && !FD->isDeleted())
     checkTypeSupport(FD->getType(), FD->getLocation(), FD);
 
+  if (FD && SummarizerPtr)
+    SummarizerPtr->SummarizeFunctionBody(FD);
+
   return dcl;
 }
 
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
new file mode 100644
index 0000000000000..ce1d514d3df9c
--- /dev/null
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -0,0 +1,8 @@
+#include "clang/Sema/SemaSummarizer.h"
+
+namespace clang {
+void SemaSummarizer::SummarizeFunctionBody(FunctionDecl *FD) const {
+  FD->dump();
+}
+
+} // namespace clang
\ No newline at end of file
diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp
index 748f59b856e83..db0490689da53 100644
--- a/clang/lib/Testing/TestAST.cpp
+++ b/clang/lib/Testing/TestAST.cpp
@@ -69,7 +69,7 @@ void createMissingComponents(CompilerInstance &Clang) {
   if (!Clang.hasASTContext())
     Clang.createASTContext();
   if (!Clang.hasSema())
-    Clang.createSema(TU_Complete, /*CodeCompleteConsumer=*/nullptr);
+    Clang.createSema(TU_Complete, /*CodeCompleteConsumer=*/nullptr, nullptr);
 }
 
 } // namespace
diff --git a/clang/unittests/CodeGen/TestCompiler.h b/clang/unittests/CodeGen/TestCompiler.h
index a6fec7fb0945d..760fa340c3d74 100644
--- a/clang/unittests/CodeGen/TestCompiler.h
+++ b/clang/unittests/CodeGen/TestCompiler.h
@@ -69,7 +69,7 @@ struct TestCompiler {
 
     compiler.setASTConsumer(std::move(Consumer));
 
-    compiler.createSema(clang::TU_Prefix, nullptr);
+    compiler.createSema(clang::TU_Prefix, nullptr, nullptr);
 
     clang::SourceManager &sm = compiler.getSourceManager();
     sm.setMainFileID(sm.createFileID(
diff --git a/clang/unittests/Frontend/CodeGenActionTest.cpp b/clang/unittests/Frontend/CodeGenActionTest.cpp
index 90818b72cd6e6..e958ea1993a4a 100644
--- a/clang/unittests/Frontend/CodeGenActionTest.cpp
+++ b/clang/unittests/Frontend/CodeGenActionTest.cpp
@@ -37,7 +37,7 @@ class NullCodeGenAction : public CodeGenAction {
     if (!CI.hasPreprocessor())
       return;
     if (!CI.hasSema())
-      CI.createSema(getTranslationUnitKind(), nullptr);
+      CI.createSema(getTranslationUnitKind(), nullptr, nullptr);
   }
 };
 
diff --git a/clang/unittests/Sema/ExternalSemaSourceTest.cpp b/clang/unittests/Sema/ExternalSemaSourceTest.cpp
index 2b271d4bf7825..d223a7135ee84 100644
--- a/clang/unittests/Sema/ExternalSemaSourceTest.cpp
+++ b/clang/unittests/Sema/ExternalSemaSourceTest.cpp
@@ -194,7 +194,7 @@ class ExternalSemaSourceInstaller : public clang::ASTFrontendAction {
   void ExecuteAction() override {
     CompilerInstance &CI = getCompilerInstance();
     ASSERT_FALSE(CI.hasSema());
-    CI.createSema(getTranslationUnitKind(), nullptr);
+    CI.createSema(getTranslationUnitKind(), nullptr, nullptr);
     ASSERT_TRUE(CI.hasDiagnostics());
     DiagnosticsEngine &Diagnostics = CI.getDiagnostics();
     DiagnosticConsumer *Client = Diagnostics.getClient();
diff --git a/clang/unittests/Sema/SemaLookupTest.cpp b/clang/unittests/Sema/SemaLookupTest.cpp
index d97b571f6a37c..96c27945421f9 100644
--- a/clang/unittests/Sema/SemaLookupTest.cpp
+++ b/clang/unittests/Sema/SemaLookupTest.cpp
@@ -22,7 +22,7 @@ class LookupAction : public ASTFrontendAction {
   void ExecuteAction() override {
     CompilerInstance &CI = getCompilerInstance();
     ASSERT_FALSE(CI.hasSema());
-    CI.createSema(getTranslationUnitKind(), nullptr);
+    CI.createSema(getTranslationUnitKind(), nullptr, nullptr);
     ASSERT_TRUE(CI.hasSema());
     Sema &S = CI.getSema();
     ParseAST(S);

>From 2592f08b25c7394f7a765a4ca1ecb9ce69657560 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sun, 8 Jun 2025 00:21:20 +0200
Subject: [PATCH 03/28] [clang][Summary] implement summary base prototype

---
 clang/include/clang/Sema/SemaSummarizer.h |  2 +-
 clang/lib/Sema/SemaSummarizer.cpp         | 57 +++++++++++++++++++++--
 2 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 3661e443bb2de..45e97529a2f1f 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -12,7 +12,7 @@ class SemaSummarizer : public SemaBase {
 
   SummaryConsumer *SummaryConsumer;
 
-  void SummarizeFunctionBody(FunctionDecl *FD) const;
+  void SummarizeFunctionBody(const FunctionDecl *FD);
 };
 } // namespace clang
 
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index ce1d514d3df9c..65ac0a7e4ec36 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -1,8 +1,59 @@
 #include "clang/Sema/SemaSummarizer.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Index/USRGeneration.h"
+#include <set>
 
 namespace clang {
-void SemaSummarizer::SummarizeFunctionBody(FunctionDecl *FD) const {
-  FD->dump();
+namespace {
+class FunctionSummary {
+  SmallVector<char> ID;
+  std::vector<std::string> FunctionAttrs;
+  std::set<SmallVector<char>> Calls;
+
+public:
+  void addCall(const clang::FunctionDecl *FD) {
+    SmallVector<char> Call;
+    index::generateUSRForDecl(FD, Call);
+    Calls.emplace(Call);
+  }
+
+  FunctionSummary(const clang::FunctionDecl *FD) {
+    index::generateUSRForDecl(FD, ID);
+  }
+};
+
+class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
+  FunctionSummary *Summary;
+
+public:
+  CallCollector(FunctionSummary &Summary) : Summary(&Summary) {}
+
+  virtual void
+  run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+    const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+    if (!Call)
+      return;
+
+    const auto *Callee = llvm::dyn_cast<FunctionDecl>(Call->getCalleeDecl());
+    Summary->addCall(Callee);
+  }
+};
+
+void CollectCalledFunctions(const FunctionDecl *FD, FunctionSummary &Summary) {
+  using namespace ast_matchers;
+  MatchFinder Finder;
+  CallCollector CC(Summary);
+
+  Finder.addMatcher(functionDecl(forEachDescendant(callExpr().bind("call"))),
+                    &CC);
+  Finder.match(*FD, FD->getASTContext());
+}
+
+} // namespace
+
+void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
+  FunctionSummary Summary(FD);
+  CollectCalledFunctions(FD, Summary);
 }
 
-} // namespace clang
\ No newline at end of file
+} // namespace clang

>From 43c1b90334a7abc7caf636f6bc15ff4a3194be13 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sun, 8 Jun 2025 14:53:27 +0200
Subject: [PATCH 04/28] [clang][Summary] implement summary inference prototype

---
 clang/include/clang/Sema/SemaSummarizer.h   | 22 ++++-
 clang/include/clang/Sema/SummaryAttribute.h | 54 ++++++++++++
 clang/lib/Sema/SemaSummarizer.cpp           | 95 +++++++++++++++------
 3 files changed, 141 insertions(+), 30 deletions(-)
 create mode 100644 clang/include/clang/Sema/SummaryAttribute.h

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 45e97529a2f1f..71ec68cf947ba 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -2,15 +2,31 @@
 #define LLVM_CLANG_SEMA_SEMASUMMARIZER_H
 
 #include "clang/Sema/SemaBase.h"
+#include "clang/Sema/SummaryAttribute.h"
 #include "clang/Sema/SummaryConsumer.h"
+#include <set>
 
 namespace clang {
+class FunctionSummary {
+  SmallVector<char> ID;
+  std::set<SummaryAttribute> FunctionAttrs;
+  std::set<SmallVector<char>> Calls;
+
+public:
+  FunctionSummary(const clang::FunctionDecl *FD);
+
+  void addAttribute(SummaryAttribute Attr) { FunctionAttrs.emplace(Attr); }
+  bool hasAttribute(SummaryAttribute Attr) { return FunctionAttrs.count(Attr); }
+
+  void addCall(const clang::FunctionDecl *FD);
+};
+
 class SemaSummarizer : public SemaBase {
 public:
-  SemaSummarizer(Sema &S, SummaryConsumer *SummaryConsumer)
-      : SemaBase(S), SummaryConsumer(SummaryConsumer) {}
+  SemaSummarizer(Sema &S, SummaryConsumer *SummaryConsumer);
 
-  SummaryConsumer *SummaryConsumer;
+  std::vector<std::unique_ptr<SummaryAttributeManager>> Attributes;
+  SummaryConsumer *TheSummaryConsumer;
 
   void SummarizeFunctionBody(const FunctionDecl *FD);
 };
diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
new file mode 100644
index 0000000000000..ed8a8125d22f1
--- /dev/null
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -0,0 +1,54 @@
+#ifndef LLVM_CLANG_SEMA_SEMASUMMARYATTRIBUTE_H
+#define LLVM_CLANG_SEMA_SEMASUMMARYATTRIBUTE_H
+
+#include "clang/AST/Decl.h"
+#include <string>
+
+namespace clang {
+enum SummaryAttribute {
+  NO_WRITE_GLOBAL,
+};
+
+class FunctionSummary;
+
+class SummaryAttributeManager {
+  inline static std::unordered_map<SummaryAttribute, std::string> AttrToStr;
+
+protected:
+  const SummaryAttribute Attr;
+  const char *Str;
+
+public:
+  SummaryAttributeManager(SummaryAttribute Attr, const char *Str)
+      : Attr(Attr), Str(Str) {
+    assert(AttrToStr.count(Attr) == 0 && "attribute already registered");
+    for (auto &&[attr, str] : AttrToStr)
+      assert(str != Str && "attribute representation is already used");
+
+    AttrToStr[Attr] = Str;
+  }
+  virtual ~SummaryAttributeManager() = default;
+
+  virtual bool predicate(const FunctionDecl *FD) = 0;
+
+  // FIXME: This should receive all the parsed summaries as well.
+  virtual bool merge(FunctionSummary &Summary) = 0;
+
+  virtual std::string serialize() const { return Str; };
+  virtual std::optional<SummaryAttribute> parse(std::string_view Input) const {
+    if (Str == Input)
+      return Attr;
+
+    return std::nullopt;
+  };
+
+  std::optional<SummaryAttribute> infer(const FunctionDecl *FD) {
+    if (predicate(FD))
+      return Attr;
+
+    return std::nullopt;
+  };
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMASUMMARYATTRIBUTEH
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 65ac0a7e4ec36..1a7dd7ba26f99 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -1,31 +1,14 @@
 #include "clang/Sema/SemaSummarizer.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Index/USRGeneration.h"
+#include "clang/Sema/SummaryConsumer.h"
 #include <set>
 
 namespace clang {
 namespace {
-class FunctionSummary {
-  SmallVector<char> ID;
-  std::vector<std::string> FunctionAttrs;
-  std::set<SmallVector<char>> Calls;
-
-public:
-  void addCall(const clang::FunctionDecl *FD) {
-    SmallVector<char> Call;
-    index::generateUSRForDecl(FD, Call);
-    Calls.emplace(Call);
-  }
-
-  FunctionSummary(const clang::FunctionDecl *FD) {
-    index::generateUSRForDecl(FD, ID);
-  }
-};
-
 class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
   FunctionSummary *Summary;
 
-public:
   CallCollector(FunctionSummary &Summary) : Summary(&Summary) {}
 
   virtual void
@@ -37,23 +20,81 @@ class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
     const auto *Callee = llvm::dyn_cast<FunctionDecl>(Call->getCalleeDecl());
     Summary->addCall(Callee);
   }
+
+public:
+  static void CollectCalledFunctions(const FunctionDecl *FD,
+                                     FunctionSummary &Summary) {
+    using namespace ast_matchers;
+    MatchFinder Finder;
+    CallCollector CC(Summary);
+
+    Finder.addMatcher(functionDecl(forEachDescendant(callExpr().bind("call"))),
+                      &CC);
+    Finder.match(*FD, FD->getASTContext());
+  }
 };
 
-void CollectCalledFunctions(const FunctionDecl *FD, FunctionSummary &Summary) {
-  using namespace ast_matchers;
-  MatchFinder Finder;
-  CallCollector CC(Summary);
+class NoWriteGlobalAttrManager : public SummaryAttributeManager {
+  class Callback : public ast_matchers::MatchFinder::MatchCallback {
+  public:
+    bool WriteGlobal = false;
 
-  Finder.addMatcher(functionDecl(forEachDescendant(callExpr().bind("call"))),
-                    &CC);
-  Finder.match(*FD, FD->getASTContext());
-}
+    void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+      const auto *Assignment =
+          Result.Nodes.getNodeAs<BinaryOperator>("assignment");
+      if (!Assignment)
+        return;
+
+      WriteGlobal = true;
+    };
+  };
 
+public:
+  NoWriteGlobalAttrManager()
+      : SummaryAttributeManager(NO_WRITE_GLOBAL, "no_write_global") {}
+
+  bool predicate(const FunctionDecl *FD) override {
+    using namespace ast_matchers;
+    MatchFinder Finder;
+    Callback CB;
+
+    Finder.addMatcher(
+        functionDecl(forEachDescendant(
+            binaryOperator(isAssignmentOperator(),
+                           hasLHS(declRefExpr(to(varDecl(hasGlobalStorage())))))
+                .bind("assignment"))),
+        &CB);
+    Finder.match(*FD, FD->getASTContext());
+    return !CB.WriteGlobal;
+  };
+
+  bool merge(FunctionSummary &Summary) override { return true; };
+};
 } // namespace
 
+void FunctionSummary::addCall(const clang::FunctionDecl *FD) {
+  SmallVector<char> Call;
+  index::generateUSRForDecl(FD, Call);
+  Calls.emplace(Call);
+}
+
+FunctionSummary::FunctionSummary(const clang::FunctionDecl *FD) {
+  index::generateUSRForDecl(FD, ID);
+}
+
+SemaSummarizer::SemaSummarizer(Sema &S, SummaryConsumer *SummaryConsumer)
+    : SemaBase(S), TheSummaryConsumer(SummaryConsumer) {
+  Attributes.emplace_back(std::make_unique<NoWriteGlobalAttrManager>());
+}
+
 void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
   FunctionSummary Summary(FD);
-  CollectCalledFunctions(FD, Summary);
+  CallCollector::CollectCalledFunctions(FD, Summary);
+
+  for (auto &&Attr : Attributes) {
+    if (const auto &InferredAttr = Attr->infer(FD))
+      Summary.addAttribute(*InferredAttr);
+  }
 }
 
 } // namespace clang

>From f1ea491e6f2cf7c6d21f25b611cd33cd6607567b Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sun, 8 Jun 2025 17:08:55 +0200
Subject: [PATCH 05/28] [clang][Summary] summary printing prototype

---
 clang/include/clang/Sema/SemaSummarizer.h   | 10 ++++++-
 clang/include/clang/Sema/SummaryAttribute.h |  3 ++-
 clang/include/clang/Sema/SummaryConsumer.h  | 30 ++++++++++++++++++++-
 clang/lib/Frontend/CompilerInstance.cpp     | 12 +++++++--
 clang/lib/Frontend/FrontendAction.cpp       |  6 -----
 clang/lib/Sema/CMakeLists.txt               |  1 +
 clang/lib/Sema/Sema.cpp                     |  5 ++++
 clang/lib/Sema/SemaSummarizer.cpp           | 13 +++++++++
 clang/lib/Sema/SummaryConsumer.cpp          | 24 +++++++++++++++++
 9 files changed, 93 insertions(+), 11 deletions(-)
 create mode 100644 clang/lib/Sema/SummaryConsumer.cpp

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 71ec68cf947ba..ef40599d982a1 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -15,8 +15,12 @@ class FunctionSummary {
 public:
   FunctionSummary(const clang::FunctionDecl *FD);
 
+  SmallVector<char> getID() const { return ID; }
+  const std::set<SummaryAttribute> &getFunctionAttrs() const { return FunctionAttrs; }
+  const std::set<SmallVector<char>> &getCalls() const { return Calls; }
+
   void addAttribute(SummaryAttribute Attr) { FunctionAttrs.emplace(Attr); }
-  bool hasAttribute(SummaryAttribute Attr) { return FunctionAttrs.count(Attr); }
+  bool hasAttribute(SummaryAttribute Attr) const { return FunctionAttrs.count(Attr); }
 
   void addCall(const clang::FunctionDecl *FD);
 };
@@ -28,7 +32,11 @@ class SemaSummarizer : public SemaBase {
   std::vector<std::unique_ptr<SummaryAttributeManager>> Attributes;
   SummaryConsumer *TheSummaryConsumer;
 
+  void ActOnStartOfSourceFile();
+  void ActOnEndOfSourceFile();
+  
   void SummarizeFunctionBody(const FunctionDecl *FD);
+
 };
 } // namespace clang
 
diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index ed8a8125d22f1..2d2fd1e4ff623 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -34,7 +34,8 @@ class SummaryAttributeManager {
   // FIXME: This should receive all the parsed summaries as well.
   virtual bool merge(FunctionSummary &Summary) = 0;
 
-  virtual std::string serialize() const { return Str; };
+  // FIXME: bad design
+  static std::string serialize(SummaryAttribute Attr) { return AttrToStr[Attr]; };
   virtual std::optional<SummaryAttribute> parse(std::string_view Input) const {
     if (Str == Input)
       return Attr;
diff --git a/clang/include/clang/Sema/SummaryConsumer.h b/clang/include/clang/Sema/SummaryConsumer.h
index 8aa2713b46c65..c2698288ce721 100644
--- a/clang/include/clang/Sema/SummaryConsumer.h
+++ b/clang/include/clang/Sema/SummaryConsumer.h
@@ -1,8 +1,36 @@
 #ifndef LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
 #define LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
 
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/JSON.h"
 namespace clang {
-class SummaryConsumer {};
+class FunctionSummary;
+
+class SummaryConsumer {
+public:
+    virtual ~SummaryConsumer() = default;
+
+    virtual void ProcessStartOfSourceFile() {};
+    virtual void ProcessFunctionSummary(const FunctionSummary&) {};
+    virtual void ProcessEndOfSourceFile() {};
+};
+
+class PrintingSummaryConsumer : public SummaryConsumer {
+public:
+    PrintingSummaryConsumer(raw_ostream &OS)
+      : SummaryConsumer() {}
+};
+
+class JSONPrintingSummaryConsumer : public PrintingSummaryConsumer {
+    llvm::json::OStream JOS;
+
+public:
+    JSONPrintingSummaryConsumer(raw_ostream &OS) : PrintingSummaryConsumer(OS), JOS(OS, 2) {}
+
+    void ProcessStartOfSourceFile() override { JOS.arrayBegin(); };
+    void ProcessFunctionSummary(const FunctionSummary&) override;
+    void ProcessEndOfSourceFile() override { JOS.arrayEnd(); };
+};
 } // namespace clang
 
 #endif // LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 917a187f49fb5..c90b8884f5731 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -743,8 +743,16 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
 }
 
 void CompilerInstance::createSummaryConsumer() {
-  TheSummaryConsumer.reset(
-      getFrontendOpts().SummaryFile.empty() ? nullptr : new SummaryConsumer());
+  const std::string& SummaryFile = getFrontendOpts().SummaryFile;
+  if(SummaryFile.empty())
+    return;
+
+  std::error_code EC;
+  // FIXME: this being static is a design error
+  static llvm::raw_fd_ostream SummaryOS(SummaryFile, EC, llvm::sys::fs::CD_CreateAlways);
+
+  if(!EC)
+    TheSummaryConsumer.reset(new JSONPrintingSummaryConsumer(SummaryOS));
 }
 
 void CompilerInstance::createSema(TranslationUnitKind TUKind,
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index aeeab901b9ed7..35b0c0373533a 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -1253,12 +1253,6 @@ void FrontendAction::EndSourceFile() {
   // Finalize the action.
   EndSourceFileAction();
 
-  if (CI.hasSema() && !CI.getFrontendOpts().SummaryFile.empty()) {
-    std::error_code EC;
-    llvm::raw_fd_ostream(CI.getFrontendOpts().SummaryFile, EC,
-                         llvm::sys::fs::CD_CreateAlways);
-  }
-
   // Sema references the ast consumer, so reset sema first.
   //
   // FIXME: There is more per-file stuff we could just drop here?
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 5237f20201fde..d6297016c015f 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -99,6 +99,7 @@ add_clang_library(clangSema
   SemaType.cpp
   SemaWasm.cpp
   SemaX86.cpp
+  SummaryConsumer.cpp
   TypeLocBuilder.cpp
 
   DEPENDS
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 2410d513c299e..ae9f8c00081b3 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1147,6 +1147,9 @@ void Sema::ActOnStartOfTranslationUnit() {
   if (getLangOpts().CPlusPlusModules &&
       getLangOpts().getCompilingModule() == LangOptions::CMK_HeaderUnit)
     HandleStartOfHeaderUnit();
+  
+  if(SummarizerPtr)
+    SummarizerPtr->ActOnStartOfSourceFile();
 }
 
 void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
@@ -1222,6 +1225,8 @@ void Sema::ActOnEndOfTranslationUnit() {
   assert(DelayedDiagnostics.getCurrentPool() == nullptr
          && "reached end of translation unit with a pool attached?");
 
+  if(SummarizerPtr)
+    SummarizerPtr->ActOnEndOfSourceFile();
   // If code completion is enabled, don't perform any end-of-translation-unit
   // work.
   if (PP.isCodeCompletionEnabled())
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 1a7dd7ba26f99..9fbb940ec3fbb 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -87,6 +87,16 @@ SemaSummarizer::SemaSummarizer(Sema &S, SummaryConsumer *SummaryConsumer)
   Attributes.emplace_back(std::make_unique<NoWriteGlobalAttrManager>());
 }
 
+void SemaSummarizer::ActOnStartOfSourceFile() {
+  if(TheSummaryConsumer)
+    TheSummaryConsumer->ProcessStartOfSourceFile();
+}
+
+void SemaSummarizer::ActOnEndOfSourceFile() {
+  if(TheSummaryConsumer)
+    TheSummaryConsumer->ProcessEndOfSourceFile();
+}
+
 void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
   FunctionSummary Summary(FD);
   CallCollector::CollectCalledFunctions(FD, Summary);
@@ -95,6 +105,9 @@ void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
     if (const auto &InferredAttr = Attr->infer(FD))
       Summary.addAttribute(*InferredAttr);
   }
+
+  if(TheSummaryConsumer)
+    TheSummaryConsumer->ProcessFunctionSummary(Summary);
 }
 
 } // namespace clang
diff --git a/clang/lib/Sema/SummaryConsumer.cpp b/clang/lib/Sema/SummaryConsumer.cpp
new file mode 100644
index 0000000000000..45aeaee502ed9
--- /dev/null
+++ b/clang/lib/Sema/SummaryConsumer.cpp
@@ -0,0 +1,24 @@
+#include "clang/Sema/SummaryConsumer.h"
+#include "clang/Sema/SemaSummarizer.h"
+
+namespace clang {
+void JSONPrintingSummaryConsumer::ProcessFunctionSummary(const FunctionSummary &Summary) {
+  JOS.object([&]{
+    JOS.attribute("id", llvm::json::Value(Summary.getID()));
+    JOS.attributeObject("attrs", [&]{
+      JOS.attributeArray("function", [&]{
+        for(auto &&Attr : Summary.getFunctionAttrs()) {
+          JOS.value(llvm::json::Value(SummaryAttributeManager::serialize(Attr)));
+        }
+      });
+    });
+    JOS.attributeArray("calls", [&]{
+      for(auto &&Call : Summary.getCalls()) {
+        JOS.object([&]{
+          JOS.attribute("id", llvm::json::Value(Call));
+        });
+      }
+    });
+  });
+}
+} // namespace clang
\ No newline at end of file

>From 6fb640433209596d293316ed07dab58e014acf2a Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sun, 8 Jun 2025 22:26:29 +0200
Subject: [PATCH 06/28] [clang][Driver][Summary] add a flag to specify the
 directory to parse the summaries from

---
 clang/include/clang/Driver/Options.td         |  4 +++
 .../include/clang/Frontend/FrontendOptions.h  |  3 ++
 clang/lib/Driver/ToolChains/Clang.cpp         |  3 ++
 clang/lib/Frontend/FrontendAction.cpp         | 29 +++++++++++++++++++
 4 files changed, 39 insertions(+)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f0c7b277e68e2..c66f098c459c2 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5941,6 +5941,10 @@ def save_temps : Flag<["-", "--"], "save-temps">, Flags<[NoXarchOption]>,
   Visibility<[ClangOption, FlangOption, FC1Option]>,
   Alias<save_temps_EQ>, AliasArgs<["cwd"]>,
   HelpText<"Alias for --save-temps=cwd">;
+def summaries_dir_EQ : Joined<["-", "--"], "summaries-dir=">, Flags<[NoXarchOption]>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Read summaries about different functions from this directory">,
+  MarshallingInfoString<FrontendOpts<"SummaryDirPath">>;
 def emit_summaries_EQ : Joined<["-", "--"], "emit-summaries=">, Flags<[NoXarchOption]>,
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Save summaries about the different functions. <arg> can be set to 'cwd' for "
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index af2451c1bde8e..20c60f823d5f3 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -537,6 +537,9 @@ class FrontendOptions {
   /// Filename to write summaries about function definitions to.
   std::string SummaryFile;
 
+  /// The directory used to load summary files.
+  std::string SummaryDirPath;
+
 public:
   FrontendOptions()
       : DisableFree(false), RelocatablePCH(false), ShowHelp(false),
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 676a4e34ddb27..48b19615ab08f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5470,6 +5470,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (Args.getLastArg(options::OPT_save_temps_EQ))
     Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
 
+  if (Args.getLastArg(options::OPT_summaries_dir_EQ))
+    Args.AddLastArg(CmdArgs, options::OPT_summaries_dir_EQ);
+
   // FIXME: This needs to be cleaned up and needs proper error handling as well.
   if (const Arg *A = Args.getLastArg(options::OPT_emit_summaries_EQ)) {
     llvm::SmallString<10> input;
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 35b0c0373533a..9cbebbabd8529 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -46,7 +46,9 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
+#include <fstream>
 #include <memory>
+#include <sstream>
 #include <system_error>
 using namespace clang;
 
@@ -962,6 +964,33 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     }
   }
 
+  // FIXME: lookup dirs recursively
+  if (!CI.getFrontendOpts().SummaryDirPath.empty()) {
+    FileManager &FileMgr = CI.getFileManager();
+
+    StringRef SummaryDirPath = CI.getFrontendOpts().SummaryDirPath;
+    if (auto SummaryDir = FileMgr.getOptionalDirectoryRef(SummaryDirPath)) {
+      std::error_code EC;
+      SmallString<128> DirNative;
+      llvm::sys::path::native(SummaryDir->getName(), DirNative);
+
+      llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
+      for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC),
+                                         DirEnd;
+           Dir != DirEnd && !EC; Dir.increment(EC)) {
+        if (llvm::sys::path::extension(Dir->path()) == ".json") {
+          std::ifstream t(Dir->path().str());
+          std::stringstream buffer;
+          buffer << t.rdbuf();
+
+          auto JSON = llvm::json::parse(buffer.str());
+          if (JSON)
+            JSON->dump();
+        }
+      }
+    }
+  }
+
   // Set up the preprocessor if needed. When parsing model files the
   // preprocessor of the original source is reused.
   if (!isModelParsingAction())

>From a45d2c0cedab95d5b0db1dba11218f97e86f64b9 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Mon, 9 Jun 2025 23:45:47 +0200
Subject: [PATCH 07/28] [clang][Summary] implement parsing the summaries

---
 .../include/clang/Frontend/CompilerInstance.h |  14 +++
 clang/include/clang/Sema/Sema.h               |   2 +
 clang/include/clang/Sema/SemaSummarizer.h     |  29 ++++-
 clang/include/clang/Sema/SummaryAttribute.h   |  35 ++----
 clang/include/clang/Sema/SummaryConsumer.h    |  11 +-
 clang/lib/Frontend/CompilerInstance.cpp       |   9 +-
 clang/lib/Frontend/FrontendAction.cpp         |  23 ++--
 clang/lib/Sema/CMakeLists.txt                 |   1 +
 clang/lib/Sema/Sema.cpp                       |   4 +-
 clang/lib/Sema/SemaDecl.cpp                   |   2 +-
 clang/lib/Sema/SemaSummarizer.cpp             | 105 +++++++++++++++---
 clang/lib/Sema/SummaryAttribute.cpp           |  19 ++++
 clang/lib/Sema/SummaryConsumer.cpp            |  18 +--
 13 files changed, 191 insertions(+), 81 deletions(-)
 create mode 100644 clang/lib/Sema/SummaryAttribute.cpp

diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index f296e6d042a54..f8f13bbc998d9 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -57,6 +57,7 @@ class Module;
 class ModuleCache;
 class Preprocessor;
 class Sema;
+class SummaryManager;
 class SourceManager;
 class TargetInfo;
 enum class DisableValidationForModuleKind;
@@ -124,6 +125,9 @@ class CompilerInstance : public ModuleLoader {
 
   /// The summary consumer.
   std::unique_ptr<SummaryConsumer> TheSummaryConsumer;
+  
+  /// The summary manager object.
+  std::unique_ptr<SummaryManager> TheSummaryManager;
 
   /// The semantic analysis object.
   std::unique_ptr<Sema> TheSema;
@@ -520,6 +524,15 @@ class CompilerInstance : public ModuleLoader {
   /// setASTContext - Replace the current AST context.
   void setASTContext(ASTContext *Value);
 
+  bool hasSummaryManager() {
+    return TheSummaryManager != nullptr;
+  }
+
+  SummaryManager &getSummaryManager() {
+    assert(TheSummaryManager && "Compiler instance has no summary manager!");
+    return *TheSummaryManager;
+  }
+
   /// Replace the current Sema; the compiler instance takes ownership
   /// of S.
   void setSema(Sema *S);
@@ -753,6 +766,7 @@ class CompilerInstance : public ModuleLoader {
       const CodeCompleteOptions &Opts, raw_ostream &OS);
 
   void createSummaryConsumer();
+  void createSummaryManager();
 
   /// Create the Sema object to be used for parsing.
   void createSema(TranslationUnitKind TUKind,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9cb2158ab4ff1..b36fce47fb792 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -125,6 +125,7 @@ class CXXBasePath;
 class CXXBasePaths;
 class CXXFieldCollector;
 class CodeCompleteConsumer;
+class SummaryManager;
 class SummaryConsumer;
 enum class ComparisonCategoryType : unsigned char;
 class ConstraintSatisfaction;
@@ -886,6 +887,7 @@ class Sema final : public SemaBase {
   Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
        TranslationUnitKind TUKind = TU_Complete,
        CodeCompleteConsumer *CompletionConsumer = nullptr,
+       SummaryManager *SummaryManager = nullptr,
        SummaryConsumer *SummaryConsumer = nullptr);
   ~Sema();
 
diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index ef40599d982a1..38e3565af0a95 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -13,6 +13,7 @@ class FunctionSummary {
   std::set<SmallVector<char>> Calls;
 
 public:
+  FunctionSummary(SmallVector<char> ID, std::set<SummaryAttribute> FunctionAttrs, std::set<SmallVector<char>> Calls);
   FunctionSummary(const clang::FunctionDecl *FD);
 
   SmallVector<char> getID() const { return ID; }
@@ -25,18 +26,36 @@ class FunctionSummary {
   void addCall(const clang::FunctionDecl *FD);
 };
 
-class SemaSummarizer : public SemaBase {
+class SummaryManager {
+  std::map<std::string, const FunctionSummary *> IDToSummary;
+  std::vector<std::unique_ptr<FunctionSummary>> FunctionSummaries;
+  
+  std::map<SummaryAttribute, const SummaryAttributeDescription *> AttrToDescription;
+  std::vector<std::unique_ptr<SummaryAttributeDescription>> AttributeDescriptions;
+
 public:
-  SemaSummarizer(Sema &S, SummaryConsumer *SummaryConsumer);
+  SummaryManager();
+
+  FunctionSummary SummarizeFunctionBody(const FunctionDecl *FD);
+  
+  void SerializeSummary(llvm::json::OStream &, const FunctionSummary &) const;
+  void ParseSummaryFromJSON(StringRef path);
+
+  void ReduceSummaries();
+};
 
-  std::vector<std::unique_ptr<SummaryAttributeManager>> Attributes;
+// FIXME: Is this class needed?
+class SemaSummarizer : public SemaBase {
+public:
+  SummaryManager *TheSummaryManager;
   SummaryConsumer *TheSummaryConsumer;
 
+  SemaSummarizer(Sema &S, SummaryManager &SummaryManager, SummaryConsumer *SummaryConsumer) 
+    : SemaBase(S), TheSummaryManager(&SummaryManager), TheSummaryConsumer(SummaryConsumer) {};
+
   void ActOnStartOfSourceFile();
   void ActOnEndOfSourceFile();
-  
   void SummarizeFunctionBody(const FunctionDecl *FD);
-
 };
 } // namespace clang
 
diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index 2d2fd1e4ff623..66d1d11334ac5 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -11,44 +11,25 @@ enum SummaryAttribute {
 
 class FunctionSummary;
 
-class SummaryAttributeManager {
-  inline static std::unordered_map<SummaryAttribute, std::string> AttrToStr;
-
+class SummaryAttributeDescription {
 protected:
   const SummaryAttribute Attr;
-  const char *Str;
+  std::string_view Serialzed;
 
 public:
-  SummaryAttributeManager(SummaryAttribute Attr, const char *Str)
-      : Attr(Attr), Str(Str) {
-    assert(AttrToStr.count(Attr) == 0 && "attribute already registered");
-    for (auto &&[attr, str] : AttrToStr)
-      assert(str != Str && "attribute representation is already used");
+  SummaryAttributeDescription(SummaryAttribute Attr, const char *Str) : Attr(Attr), Serialzed(Str) {}
+  virtual ~SummaryAttributeDescription() = default;
 
-    AttrToStr[Attr] = Str;
-  }
-  virtual ~SummaryAttributeManager() = default;
+  SummaryAttribute getAttribute() { return Attr; };
 
   virtual bool predicate(const FunctionDecl *FD) = 0;
+  std::optional<SummaryAttribute> infer(const FunctionDecl *FD);
 
   // FIXME: This should receive all the parsed summaries as well.
   virtual bool merge(FunctionSummary &Summary) = 0;
 
-  // FIXME: bad design
-  static std::string serialize(SummaryAttribute Attr) { return AttrToStr[Attr]; };
-  virtual std::optional<SummaryAttribute> parse(std::string_view Input) const {
-    if (Str == Input)
-      return Attr;
-
-    return std::nullopt;
-  };
-
-  std::optional<SummaryAttribute> infer(const FunctionDecl *FD) {
-    if (predicate(FD))
-      return Attr;
-
-    return std::nullopt;
-  };
+  virtual std::string serialize();
+  virtual std::optional<SummaryAttribute> parse(std::string_view input);
 };
 } // namespace clang
 
diff --git a/clang/include/clang/Sema/SummaryConsumer.h b/clang/include/clang/Sema/SummaryConsumer.h
index c2698288ce721..85c48b3c1b939 100644
--- a/clang/include/clang/Sema/SummaryConsumer.h
+++ b/clang/include/clang/Sema/SummaryConsumer.h
@@ -5,9 +5,14 @@
 #include "llvm/Support/JSON.h"
 namespace clang {
 class FunctionSummary;
+class SummaryManager;
 
 class SummaryConsumer {
+protected:
+    const SummaryManager *TheSummaryManager;
+
 public:
+    SummaryConsumer(const SummaryManager &SummaryManager) : TheSummaryManager(&SummaryManager) {}
     virtual ~SummaryConsumer() = default;
 
     virtual void ProcessStartOfSourceFile() {};
@@ -17,15 +22,15 @@ class SummaryConsumer {
 
 class PrintingSummaryConsumer : public SummaryConsumer {
 public:
-    PrintingSummaryConsumer(raw_ostream &OS)
-      : SummaryConsumer() {}
+    PrintingSummaryConsumer(const SummaryManager &SummaryManager, raw_ostream &OS)
+      : SummaryConsumer(SummaryManager) {}
 };
 
 class JSONPrintingSummaryConsumer : public PrintingSummaryConsumer {
     llvm::json::OStream JOS;
 
 public:
-    JSONPrintingSummaryConsumer(raw_ostream &OS) : PrintingSummaryConsumer(OS), JOS(OS, 2) {}
+    JSONPrintingSummaryConsumer(const SummaryManager &SummaryManager, raw_ostream &OS) : PrintingSummaryConsumer(SummaryManager, OS), JOS(OS, 2) {}
 
     void ProcessStartOfSourceFile() override { JOS.arrayBegin(); };
     void ProcessFunctionSummary(const FunctionSummary&) override;
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index c90b8884f5731..deed94e1f0b42 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -37,6 +37,7 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/ParsedAttr.h"
 #include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaSummarizer.h"
 #include "clang/Sema/SummaryConsumer.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/GlobalModuleIndex.h"
@@ -752,14 +753,18 @@ void CompilerInstance::createSummaryConsumer() {
   static llvm::raw_fd_ostream SummaryOS(SummaryFile, EC, llvm::sys::fs::CD_CreateAlways);
 
   if(!EC)
-    TheSummaryConsumer.reset(new JSONPrintingSummaryConsumer(SummaryOS));
+    TheSummaryConsumer.reset(new JSONPrintingSummaryConsumer(getSummaryManager(), SummaryOS));
+}
+
+void CompilerInstance::createSummaryManager() {
+  TheSummaryManager.reset(new SummaryManager());
 }
 
 void CompilerInstance::createSema(TranslationUnitKind TUKind,
                                   CodeCompleteConsumer *CompletionConsumer,
                                   SummaryConsumer *SummaryConsumer) {
   TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
-                         TUKind, CompletionConsumer, SummaryConsumer));
+                         TUKind, CompletionConsumer, hasSummaryManager() ? &getSummaryManager() : nullptr, SummaryConsumer));
 
   // Set up API notes.
   TheSema->APINotes.setSwiftVersion(getAPINotesOpts().SwiftVersion);
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 9cbebbabd8529..58aac1b8cd1b1 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -35,6 +35,7 @@
 #include "clang/Parse/ParseAST.h"
 #include "clang/Sema/HLSLExternalSemaSource.h"
 #include "clang/Sema/MultiplexExternalSemaSource.h"
+#include "clang/Sema/SemaSummarizer.h"
 #include "clang/Serialization/ASTDeserializationListener.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/GlobalModuleIndex.h"
@@ -46,9 +47,7 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
-#include <fstream>
 #include <memory>
-#include <sstream>
 #include <system_error>
 using namespace clang;
 
@@ -894,6 +893,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     }
   }
 
+  if(!CI.hasSummaryManager()) {
+    CI.createSummaryManager();
+  }
+
   // Set up embedding for any specified files. Do this before we load any
   // source files, including the primary module map for the compilation.
   for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
@@ -978,16 +981,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
       for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC),
                                          DirEnd;
            Dir != DirEnd && !EC; Dir.increment(EC)) {
-        if (llvm::sys::path::extension(Dir->path()) == ".json") {
-          std::ifstream t(Dir->path().str());
-          std::stringstream buffer;
-          buffer << t.rdbuf();
-
-          auto JSON = llvm::json::parse(buffer.str());
-          if (JSON)
-            JSON->dump();
-        }
+        if (llvm::sys::path::extension(Dir->path()) == ".json")
+          CI.getSummaryManager().ParseSummaryFromJSON(Dir->path());
       }
+
+      CI.getSummaryManager().ReduceSummaries();
     }
   }
 
@@ -1362,6 +1360,9 @@ void ASTFrontendAction::ExecuteAction() {
   if (CI.hasCodeCompletionConsumer())
     CompletionConsumer = &CI.getCodeCompletionConsumer();
 
+  if(!CI.hasSummaryManager()) {
+    CI.createSummaryManager();
+  }
   CI.createSummaryConsumer();
 
   // Use a code completion consumer?
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index d6297016c015f..bf8f73dc985db 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -99,6 +99,7 @@ add_clang_library(clangSema
   SemaType.cpp
   SemaWasm.cpp
   SemaX86.cpp
+  SummaryAttribute.cpp
   SummaryConsumer.cpp
   TypeLocBuilder.cpp
 
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index ae9f8c00081b3..5b3f1a4dca36e 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -250,6 +250,7 @@ const uint64_t Sema::MaximumAlignment;
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
            TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter,
+           SummaryManager *SummaryManager,
            SummaryConsumer *SummaryConsumer)
     : SemaBase(*this), CollectStats(false), TUKind(TUKind),
       CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
@@ -265,8 +266,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       BPFPtr(std::make_unique<SemaBPF>(*this)),
       CodeCompletionPtr(
           std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
-      SummarizerPtr(SummaryConsumer ? std::make_unique<SemaSummarizer>(
-                                          *this, SummaryConsumer)
+      SummarizerPtr(SummaryManager ? std::make_unique<SemaSummarizer>(*this, *SummaryManager, SummaryConsumer)
                                     : nullptr),
       CUDAPtr(std::make_unique<SemaCUDA>(*this)),
       DirectXPtr(std::make_unique<SemaDirectX>(*this)),
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index bb80fd2a46f58..45f1523868f75 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16695,7 +16695,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
   if (FD && !FD->isDeleted())
     checkTypeSupport(FD->getType(), FD->getLocation(), FD);
 
-  if (FD && SummarizerPtr)
+  if (FD && SummarizerPtr && SummarizerPtr->TheSummaryConsumer)
     SummarizerPtr->SummarizeFunctionBody(FD);
 
   return dcl;
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 9fbb940ec3fbb..b4ad0d4a6db2f 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -2,7 +2,10 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Index/USRGeneration.h"
 #include "clang/Sema/SummaryConsumer.h"
+#include "clang/Sema/SummaryAttribute.h"
 #include <set>
+#include <fstream>
+#include <sstream>
 
 namespace clang {
 namespace {
@@ -34,7 +37,7 @@ class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
   }
 };
 
-class NoWriteGlobalAttrManager : public SummaryAttributeManager {
+class NoWriteGlobalDescription : public SummaryAttributeDescription {
   class Callback : public ast_matchers::MatchFinder::MatchCallback {
   public:
     bool WriteGlobal = false;
@@ -50,8 +53,8 @@ class NoWriteGlobalAttrManager : public SummaryAttributeManager {
   };
 
 public:
-  NoWriteGlobalAttrManager()
-      : SummaryAttributeManager(NO_WRITE_GLOBAL, "no_write_global") {}
+  NoWriteGlobalDescription()
+      : SummaryAttributeDescription(NO_WRITE_GLOBAL, "no_write_global") {}
 
   bool predicate(const FunctionDecl *FD) override {
     using namespace ast_matchers;
@@ -78,13 +81,95 @@ void FunctionSummary::addCall(const clang::FunctionDecl *FD) {
   Calls.emplace(Call);
 }
 
+FunctionSummary::FunctionSummary(SmallVector<char> ID, std::set<SummaryAttribute> FunctionAttrs, std::set<SmallVector<char>> Calls) :
+  ID(std::move(ID)), FunctionAttrs(std::move(FunctionAttrs)), Calls(std::move(Calls)) {}
+
 FunctionSummary::FunctionSummary(const clang::FunctionDecl *FD) {
   index::generateUSRForDecl(FD, ID);
 }
 
-SemaSummarizer::SemaSummarizer(Sema &S, SummaryConsumer *SummaryConsumer)
-    : SemaBase(S), TheSummaryConsumer(SummaryConsumer) {
-  Attributes.emplace_back(std::make_unique<NoWriteGlobalAttrManager>());
+SummaryManager::SummaryManager() {
+  AttributeDescriptions.emplace_back(std::make_unique<NoWriteGlobalDescription>());
+
+  for(auto &&AttrDescr : AttributeDescriptions)
+    AttrToDescription[AttrDescr->getAttribute()] = AttrDescr.get();
+}
+
+FunctionSummary SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
+  auto Summary = std::make_unique<FunctionSummary>(FD);
+  CallCollector::CollectCalledFunctions(FD, *Summary);
+
+  for (auto &&AttrDesc : AttributeDescriptions) {
+    if (const auto &Attr = AttrDesc->infer(FD))
+      Summary->addAttribute(*Attr);
+  }
+
+  // FIXME: This is duplicated and hurts my eyes regardless
+  std::string key(Summary->getID().begin(), Summary->getID().size());
+  auto *SummaryPtr = FunctionSummaries.emplace_back(std::move(Summary)).get();
+  IDToSummary[key] = SummaryPtr;
+  return *SummaryPtr;
+}
+
+void SummaryManager::SerializeSummary(llvm::json::OStream &JOS, const FunctionSummary &Summary) const {
+  JOS.object([&]{
+    JOS.attribute("id", llvm::json::Value(Summary.getID()));
+    JOS.attributeObject("attrs", [&]{
+      JOS.attributeArray("function", [&]{
+        for(auto &&Attr : Summary.getFunctionAttrs()) {
+          JOS.value(llvm::json::Value(AttributeDescriptions[Attr]->serialize()));
+        }
+      });
+    });
+    JOS.attributeArray("calls", [&]{
+      for(auto &&Call : Summary.getCalls()) {
+        JOS.object([&]{
+          JOS.attribute("id", llvm::json::Value(Call));
+        });
+      }
+    });
+  });
+}
+
+void SummaryManager::ParseSummaryFromJSON(StringRef path) {
+  std::ifstream t(path.str());
+  std::stringstream buffer;
+  buffer << t.rdbuf();
+
+  auto JSON = llvm::json::parse(buffer.str());
+  if (!JSON)
+    return;
+
+  llvm::json::Array *Summaries = JSON->getAsArray();
+  for(auto it = Summaries->begin(); it != Summaries->end(); ++it) {
+    llvm::json::Object *Summary = it->getAsObject();
+
+    SmallString<128> ID(*Summary->getString("id"));
+    std::set<SummaryAttribute> FunctionAttrs;
+    llvm::json::Array *FunctionAttributes = Summary->getObject("attrs")->getArray("function");
+    for(auto attrIt = FunctionAttributes->begin(); attrIt != FunctionAttributes->end(); ++attrIt) {
+      for(auto &&AttrDesc : AttributeDescriptions) {
+        if(auto Attr = AttrDesc->parse(*attrIt->getAsString()))
+          FunctionAttrs.emplace(*Attr);
+      }
+    }
+
+    std::set<SmallVector<char>> Calls;
+    llvm::json::Array *CallEntries = Summary->getArray("calls");
+    for(auto callIt = CallEntries->begin(); callIt != CallEntries->end(); ++callIt) {
+      auto *Obj = callIt->getAsObject();
+      Calls.emplace(SmallString<128>(*Obj->getString("id")));
+    }
+    
+    std::string key = ID.str().str();
+    auto ParsedSummary = std::make_unique<FunctionSummary>(std::move(ID), std::move(FunctionAttrs), std::move(Calls));
+    auto *ParsedSummaryPtr = FunctionSummaries.emplace_back(std::move(ParsedSummary)).get();
+    IDToSummary[key] = ParsedSummaryPtr;
+  }
+}
+
+void SummaryManager::ReduceSummaries() {
+  // FIXME: implement
 }
 
 void SemaSummarizer::ActOnStartOfSourceFile() {
@@ -98,13 +183,7 @@ void SemaSummarizer::ActOnEndOfSourceFile() {
 }
 
 void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
-  FunctionSummary Summary(FD);
-  CallCollector::CollectCalledFunctions(FD, Summary);
-
-  for (auto &&Attr : Attributes) {
-    if (const auto &InferredAttr = Attr->infer(FD))
-      Summary.addAttribute(*InferredAttr);
-  }
+  FunctionSummary Summary = TheSummaryManager->SummarizeFunctionBody(FD);
 
   if(TheSummaryConsumer)
     TheSummaryConsumer->ProcessFunctionSummary(Summary);
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Sema/SummaryAttribute.cpp
new file mode 100644
index 0000000000000..4affec7b4ffb7
--- /dev/null
+++ b/clang/lib/Sema/SummaryAttribute.cpp
@@ -0,0 +1,19 @@
+#include "clang/Sema/SummaryAttribute.h"
+
+namespace clang {
+std::string SummaryAttributeDescription::serialize() { return std::string(Serialzed); }
+
+std::optional<SummaryAttribute> SummaryAttributeDescription::parse(std::string_view input) {
+  if(input == Serialzed)
+    return Attr;
+
+  return std::nullopt;
+}
+
+std::optional<SummaryAttribute> SummaryAttributeDescription::infer(const FunctionDecl *FD) {
+  if (predicate(FD))
+    return Attr;
+
+  return std::nullopt;
+}
+} // namespace clang
\ No newline at end of file
diff --git a/clang/lib/Sema/SummaryConsumer.cpp b/clang/lib/Sema/SummaryConsumer.cpp
index 45aeaee502ed9..37646c1e07a7f 100644
--- a/clang/lib/Sema/SummaryConsumer.cpp
+++ b/clang/lib/Sema/SummaryConsumer.cpp
@@ -3,22 +3,6 @@
 
 namespace clang {
 void JSONPrintingSummaryConsumer::ProcessFunctionSummary(const FunctionSummary &Summary) {
-  JOS.object([&]{
-    JOS.attribute("id", llvm::json::Value(Summary.getID()));
-    JOS.attributeObject("attrs", [&]{
-      JOS.attributeArray("function", [&]{
-        for(auto &&Attr : Summary.getFunctionAttrs()) {
-          JOS.value(llvm::json::Value(SummaryAttributeManager::serialize(Attr)));
-        }
-      });
-    });
-    JOS.attributeArray("calls", [&]{
-      for(auto &&Call : Summary.getCalls()) {
-        JOS.object([&]{
-          JOS.attribute("id", llvm::json::Value(Call));
-        });
-      }
-    });
-  });
+  TheSummaryManager->SerializeSummary(JOS, Summary);
 }
 } // namespace clang
\ No newline at end of file

>From e6b21071a455f1aeae544dec93cba08ccf985008 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Tue, 10 Jun 2025 23:30:34 +0200
Subject: [PATCH 08/28] [clang][Summary] implement reduction prototype

---
 clang/include/clang/Sema/SemaSummarizer.h   |  6 +++
 clang/include/clang/Sema/SummaryAttribute.h |  3 +-
 clang/lib/Frontend/FrontendAction.cpp       | 14 +++++++
 clang/lib/Sema/SemaSummarizer.cpp           | 42 ++++++++++++++++++++-
 4 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 38e3565af0a95..7d2f8252dc957 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -20,6 +20,7 @@ class FunctionSummary {
   const std::set<SummaryAttribute> &getFunctionAttrs() const { return FunctionAttrs; }
   const std::set<SmallVector<char>> &getCalls() const { return Calls; }
 
+  void clearAttributes() { FunctionAttrs.clear(); }
   void addAttribute(SummaryAttribute Attr) { FunctionAttrs.emplace(Attr); }
   bool hasAttribute(SummaryAttribute Attr) const { return FunctionAttrs.count(Attr); }
 
@@ -42,6 +43,11 @@ class SummaryManager {
   void ParseSummaryFromJSON(StringRef path);
 
   void ReduceSummaries();
+
+  // FIXME: debug only, remove later
+  const std::vector<std::unique_ptr<FunctionSummary>> &getSummaries() {
+    return FunctionSummaries;
+  }
 };
 
 // FIXME: Is this class needed?
diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index 66d1d11334ac5..beb735c00933c 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -25,8 +25,7 @@ class SummaryAttributeDescription {
   virtual bool predicate(const FunctionDecl *FD) = 0;
   std::optional<SummaryAttribute> infer(const FunctionDecl *FD);
 
-  // FIXME: This should receive all the parsed summaries as well.
-  virtual bool merge(FunctionSummary &Summary) = 0;
+  virtual bool merge(const FunctionSummary &Summary) const = 0;
 
   virtual std::string serialize();
   virtual std::optional<SummaryAttribute> parse(std::string_view input);
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 58aac1b8cd1b1..7af4a79f83eec 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -985,7 +985,21 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
           CI.getSummaryManager().ParseSummaryFromJSON(Dir->path());
       }
 
+      // FIXME: debug only, remove later
+      for (auto &&S : CI.getSummaryManager().getSummaries()) {
+        llvm::json::OStream Out(llvm::errs());
+        CI.getSummaryManager().SerializeSummary(Out, *S);
+      }
+      llvm::errs() << '\n';
+
       CI.getSummaryManager().ReduceSummaries();
+
+      // FIXME: debug only, remove later
+      for (auto &&S : CI.getSummaryManager().getSummaries()) {
+        llvm::json::OStream Out(llvm::errs());
+        CI.getSummaryManager().SerializeSummary(Out, *S);
+      }
+      llvm::errs() << '\n';
     }
   }
 
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index b4ad0d4a6db2f..569d272b36bb3 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -71,7 +71,9 @@ class NoWriteGlobalDescription : public SummaryAttributeDescription {
     return !CB.WriteGlobal;
   };
 
-  bool merge(FunctionSummary &Summary) override { return true; };
+  bool merge(const FunctionSummary &Summary) const override {
+    return Summary.getFunctionAttrs().count(Attr);
+  };
 };
 } // namespace
 
@@ -169,7 +171,43 @@ void SummaryManager::ParseSummaryFromJSON(StringRef path) {
 }
 
 void SummaryManager::ReduceSummaries() {
-  // FIXME: implement
+  bool changed = true;
+  while (changed) {
+    changed = false;
+
+    for (auto &&Function : FunctionSummaries) {
+      for (auto &&call : Function->getCalls()) {
+        // FIXME: This is duplicated and hurts my eyes regardless
+        std::string key(call.begin(), call.size());
+
+        // If we don't have a summary about a called function, we forget
+        // everything about the current one as well.
+        if (!IDToSummary.count(key)) {
+          changed = true;
+          Function->clearAttributes();
+          break;
+        }
+
+        const FunctionSummary *callSummary = IDToSummary.at(key);
+
+        std::set<SummaryAttribute> reducedAttrs;
+        for (auto &&attr : Function->getFunctionAttrs()) {
+          // FIXME: handle union style attributes...
+          if (AttrToDescription[attr]->merge(*callSummary))
+            reducedAttrs.emplace(attr);
+        }
+
+        if (reducedAttrs != Function->getFunctionAttrs()) {
+          Function->clearAttributes();
+
+          for (auto &&attr : reducedAttrs)
+            Function->addAttribute(attr);
+
+          changed = true;
+        }
+      }
+    }
+  }
 }
 
 void SemaSummarizer::ActOnStartOfSourceFile() {

>From da80bdbf6e7749fc9e81ec6bfdeb211b999d637d Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 12 Jun 2025 00:31:33 +0200
Subject: [PATCH 09/28] [clang][Summary] make `SummaryManager` own the
 attributes

---
 clang/include/clang/Sema/SemaSummarizer.h   |  22 +--
 clang/include/clang/Sema/SummaryAttribute.h |  38 +++--
 clang/lib/Sema/SemaSummarizer.cpp           | 168 ++++++++------------
 clang/lib/Sema/SummaryAttribute.cpp         |  33 ++--
 4 files changed, 130 insertions(+), 131 deletions(-)

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 7d2f8252dc957..42f668009d2f2 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -9,35 +9,37 @@
 namespace clang {
 class FunctionSummary {
   SmallVector<char> ID;
-  std::set<SummaryAttribute> FunctionAttrs;
+  std::set<const SummaryAttribute *> FunctionAttrs;
   std::set<SmallVector<char>> Calls;
 
 public:
-  FunctionSummary(SmallVector<char> ID, std::set<SummaryAttribute> FunctionAttrs, std::set<SmallVector<char>> Calls);
+  FunctionSummary(SmallVector<char> ID, std::set<const SummaryAttribute *> FunctionAttrs, std::set<SmallVector<char>> Calls);
   FunctionSummary(const clang::FunctionDecl *FD);
 
   SmallVector<char> getID() const { return ID; }
-  const std::set<SummaryAttribute> &getFunctionAttrs() const { return FunctionAttrs; }
+  const std::set<const SummaryAttribute *> &getFunctionAttrs() const { return FunctionAttrs; }
   const std::set<SmallVector<char>> &getCalls() const { return Calls; }
 
-  void clearAttributes() { FunctionAttrs.clear(); }
-  void addAttribute(SummaryAttribute Attr) { FunctionAttrs.emplace(Attr); }
-  bool hasAttribute(SummaryAttribute Attr) const { return FunctionAttrs.count(Attr); }
+  void replaceAttributes(std::set<const SummaryAttribute *> Attrs) { FunctionAttrs = std::move(Attrs); }
+  void addAttribute(const SummaryAttribute * Attr) { FunctionAttrs.emplace(Attr); }
 
   void addCall(const clang::FunctionDecl *FD);
 };
 
 class SummaryManager {
-  std::map<std::string, const FunctionSummary *> IDToSummary;
+  std::map<SmallVector<char>, const FunctionSummary *> IDToSummary;
   std::vector<std::unique_ptr<FunctionSummary>> FunctionSummaries;
   
-  std::map<SummaryAttribute, const SummaryAttributeDescription *> AttrToDescription;
-  std::vector<std::unique_ptr<SummaryAttributeDescription>> AttributeDescriptions;
+  std::map<SummaryAttributeKind, const SummaryAttribute *> KindToAttribute;
+  std::vector<std::unique_ptr<SummaryAttribute>> Attributes;
 
+  void SaveSummary(std::unique_ptr<FunctionSummary> Summary);
+  bool ReduceFunctionSummary(FunctionSummary &FunctionSummary);
 public:
   SummaryManager();
 
-  FunctionSummary SummarizeFunctionBody(const FunctionDecl *FD);
+  const FunctionSummary *GetSummary(const FunctionDecl *FD) const;
+  void SummarizeFunctionBody(const FunctionDecl *FD);
   
   void SerializeSummary(llvm::json::OStream &, const FunctionSummary &) const;
   void ParseSummaryFromJSON(StringRef path);
diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index beb735c00933c..bfe7ecf84e795 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -2,33 +2,47 @@
 #define LLVM_CLANG_SEMA_SEMASUMMARYATTRIBUTE_H
 
 #include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
 #include <string>
 
 namespace clang {
-enum SummaryAttribute {
+enum SummaryAttributeKind {
   NO_WRITE_GLOBAL,
 };
 
 class FunctionSummary;
 
-class SummaryAttributeDescription {
-protected:
-  const SummaryAttribute Attr;
+class SummaryAttribute {
+  const SummaryAttributeKind Kind;
   std::string_view Serialzed;
 
 public:
-  SummaryAttributeDescription(SummaryAttribute Attr, const char *Str) : Attr(Attr), Serialzed(Str) {}
-  virtual ~SummaryAttributeDescription() = default;
+  SummaryAttribute(SummaryAttributeKind Attr, const char *Str) : Kind(Attr), Serialzed(Str) {}
+  virtual ~SummaryAttribute() = default;
+  
+  SummaryAttributeKind getKind() { return Kind; }
 
-  SummaryAttribute getAttribute() { return Attr; };
+  virtual bool infer(const FunctionDecl *FD) const = 0;
+  virtual bool merge(const FunctionSummary &Summary) const = 0;
 
-  virtual bool predicate(const FunctionDecl *FD) = 0;
-  std::optional<SummaryAttribute> infer(const FunctionDecl *FD);
+  virtual std::string serialize() const { return std::string(Serialzed); };
+  virtual bool parse(std::string_view input) const { return input == Serialzed; };
+};
 
-  virtual bool merge(const FunctionSummary &Summary) const = 0;
+class NoWriteGlobalDescription : public SummaryAttribute {
+  class Callback : public ast_matchers::MatchFinder::MatchCallback {
+  public:
+    bool WriteGlobal = false;
 
-  virtual std::string serialize();
-  virtual std::optional<SummaryAttribute> parse(std::string_view input);
+    void run(const ast_matchers::MatchFinder::MatchResult &Result) override final;
+  };
+
+public:
+  NoWriteGlobalDescription()
+  : SummaryAttribute(NO_WRITE_GLOBAL, "no_write_global") {}
+  
+  bool infer(const FunctionDecl *FD) const override final;
+  bool merge(const FunctionSummary &Summary) const override final;
 };
 } // namespace clang
 
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 569d272b36bb3..97b2d50bd7602 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -37,80 +37,54 @@ class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
   }
 };
 
-class NoWriteGlobalDescription : public SummaryAttributeDescription {
-  class Callback : public ast_matchers::MatchFinder::MatchCallback {
-  public:
-    bool WriteGlobal = false;
-
-    void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
-      const auto *Assignment =
-          Result.Nodes.getNodeAs<BinaryOperator>("assignment");
-      if (!Assignment)
-        return;
-
-      WriteGlobal = true;
-    };
-  };
-
-public:
-  NoWriteGlobalDescription()
-      : SummaryAttributeDescription(NO_WRITE_GLOBAL, "no_write_global") {}
-
-  bool predicate(const FunctionDecl *FD) override {
-    using namespace ast_matchers;
-    MatchFinder Finder;
-    Callback CB;
-
-    Finder.addMatcher(
-        functionDecl(forEachDescendant(
-            binaryOperator(isAssignmentOperator(),
-                           hasLHS(declRefExpr(to(varDecl(hasGlobalStorage())))))
-                .bind("assignment"))),
-        &CB);
-    Finder.match(*FD, FD->getASTContext());
-    return !CB.WriteGlobal;
-  };
-
-  bool merge(const FunctionSummary &Summary) const override {
-    return Summary.getFunctionAttrs().count(Attr);
-  };
-};
+SmallVector<char> GetUSR(const FunctionDecl *FD) {
+  SmallVector<char> USR;
+  index::generateUSRForDecl(FD, USR);
+  return USR;
+}
 } // namespace
 
 void FunctionSummary::addCall(const clang::FunctionDecl *FD) {
-  SmallVector<char> Call;
-  index::generateUSRForDecl(FD, Call);
-  Calls.emplace(Call);
+  Calls.emplace(GetUSR(FD));
 }
 
-FunctionSummary::FunctionSummary(SmallVector<char> ID, std::set<SummaryAttribute> FunctionAttrs, std::set<SmallVector<char>> Calls) :
+FunctionSummary::FunctionSummary(SmallVector<char> ID, std::set<const SummaryAttribute *> FunctionAttrs, std::set<SmallVector<char>> Calls) :
   ID(std::move(ID)), FunctionAttrs(std::move(FunctionAttrs)), Calls(std::move(Calls)) {}
 
-FunctionSummary::FunctionSummary(const clang::FunctionDecl *FD) {
-  index::generateUSRForDecl(FD, ID);
-}
+FunctionSummary::FunctionSummary(const clang::FunctionDecl *FD) : ID(GetUSR(FD)) {}
 
 SummaryManager::SummaryManager() {
-  AttributeDescriptions.emplace_back(std::make_unique<NoWriteGlobalDescription>());
+  Attributes.emplace_back(std::make_unique<NoWriteGlobalDescription>());
+
+  for(auto &&Attr : Attributes) {
+    assert(KindToAttribute.count(Attr->getKind()) == 0 && "Attr already registered");
+    KindToAttribute[Attr->getKind()] = Attr.get();
+  }
+}
 
-  for(auto &&AttrDescr : AttributeDescriptions)
-    AttrToDescription[AttrDescr->getAttribute()] = AttrDescr.get();
+void SummaryManager::SaveSummary(std::unique_ptr<FunctionSummary> Summary) {
+  auto *SummaryPtr = FunctionSummaries.emplace_back(std::move(Summary)).get();
+  IDToSummary[SummaryPtr->getID()] = SummaryPtr;
 }
 
-FunctionSummary SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
+const FunctionSummary *SummaryManager::GetSummary(const FunctionDecl *FD) const { 
+  auto USR = GetUSR(FD);
+  if(!IDToSummary.count(USR))
+    return nullptr;
+
+  return IDToSummary.at(USR);
+}
+
+void SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
   auto Summary = std::make_unique<FunctionSummary>(FD);
   CallCollector::CollectCalledFunctions(FD, *Summary);
 
-  for (auto &&AttrDesc : AttributeDescriptions) {
-    if (const auto &Attr = AttrDesc->infer(FD))
-      Summary->addAttribute(*Attr);
+  for (auto &&Attr : Attributes) {
+    if (Attr->infer(FD))
+      Summary->addAttribute(Attr.get());
   }
 
-  // FIXME: This is duplicated and hurts my eyes regardless
-  std::string key(Summary->getID().begin(), Summary->getID().size());
-  auto *SummaryPtr = FunctionSummaries.emplace_back(std::move(Summary)).get();
-  IDToSummary[key] = SummaryPtr;
-  return *SummaryPtr;
+  SaveSummary(std::move(Summary));
 }
 
 void SummaryManager::SerializeSummary(llvm::json::OStream &JOS, const FunctionSummary &Summary) const {
@@ -119,7 +93,7 @@ void SummaryManager::SerializeSummary(llvm::json::OStream &JOS, const FunctionSu
     JOS.attributeObject("attrs", [&]{
       JOS.attributeArray("function", [&]{
         for(auto &&Attr : Summary.getFunctionAttrs()) {
-          JOS.value(llvm::json::Value(AttributeDescriptions[Attr]->serialize()));
+          JOS.value(llvm::json::Value(Attr->serialize()));
         }
       });
     });
@@ -147,12 +121,12 @@ void SummaryManager::ParseSummaryFromJSON(StringRef path) {
     llvm::json::Object *Summary = it->getAsObject();
 
     SmallString<128> ID(*Summary->getString("id"));
-    std::set<SummaryAttribute> FunctionAttrs;
+    std::set<const SummaryAttribute *> FunctionAttrs;
     llvm::json::Array *FunctionAttributes = Summary->getObject("attrs")->getArray("function");
     for(auto attrIt = FunctionAttributes->begin(); attrIt != FunctionAttributes->end(); ++attrIt) {
-      for(auto &&AttrDesc : AttributeDescriptions) {
-        if(auto Attr = AttrDesc->parse(*attrIt->getAsString()))
-          FunctionAttrs.emplace(*Attr);
+      for(auto &&Attr : Attributes) {
+        if(Attr->parse(*attrIt->getAsString()))
+          FunctionAttrs.emplace(Attr.get());
       }
     }
 
@@ -163,51 +137,47 @@ void SummaryManager::ParseSummaryFromJSON(StringRef path) {
       Calls.emplace(SmallString<128>(*Obj->getString("id")));
     }
     
-    std::string key = ID.str().str();
-    auto ParsedSummary = std::make_unique<FunctionSummary>(std::move(ID), std::move(FunctionAttrs), std::move(Calls));
-    auto *ParsedSummaryPtr = FunctionSummaries.emplace_back(std::move(ParsedSummary)).get();
-    IDToSummary[key] = ParsedSummaryPtr;
+    SaveSummary(std::make_unique<FunctionSummary>(std::move(ID), std::move(FunctionAttrs), std::move(Calls)));
   }
 }
 
-void SummaryManager::ReduceSummaries() {
-  bool changed = true;
-  while (changed) {
-    changed = false;
-
-    for (auto &&Function : FunctionSummaries) {
-      for (auto &&call : Function->getCalls()) {
-        // FIXME: This is duplicated and hurts my eyes regardless
-        std::string key(call.begin(), call.size());
-
-        // If we don't have a summary about a called function, we forget
-        // everything about the current one as well.
-        if (!IDToSummary.count(key)) {
-          changed = true;
-          Function->clearAttributes();
-          break;
-        }
+bool SummaryManager::ReduceFunctionSummary(FunctionSummary &Function) {
+  bool changed = false;
 
-        const FunctionSummary *callSummary = IDToSummary.at(key);
+  for (auto &&call : Function.getCalls()) {
+    std::set<const SummaryAttribute *> reducedAttrs;
 
-        std::set<SummaryAttribute> reducedAttrs;
-        for (auto &&attr : Function->getFunctionAttrs()) {
-          // FIXME: handle union style attributes...
-          if (AttrToDescription[attr]->merge(*callSummary))
-            reducedAttrs.emplace(attr);
-        }
+    // If we don't have a summary about a called function, we forget
+    // everything about the current one as well.
+    if (!IDToSummary.count(call)) {
+      Function.replaceAttributes(std::move(reducedAttrs));
+      return true;
+    }
 
-        if (reducedAttrs != Function->getFunctionAttrs()) {
-          Function->clearAttributes();
+    const FunctionSummary *callSummary = IDToSummary[call];
 
-          for (auto &&attr : reducedAttrs)
-            Function->addAttribute(attr);
+    for (auto &&Attr : Function.getFunctionAttrs()) {
+      if (Attr->merge(*callSummary))
+        reducedAttrs.emplace(Attr);
+    }
 
-          changed = true;
-        }
-      }
+    if (reducedAttrs != Function.getFunctionAttrs()) {
+      Function.replaceAttributes(std::move(reducedAttrs));
+      changed = true;
     }
   }
+
+  return changed;
+}
+
+void SummaryManager::ReduceSummaries() {
+  bool changed = true;
+  while (changed) {
+    changed = false;
+
+    for (auto &&Function : FunctionSummaries)
+      changed |= ReduceFunctionSummary(*Function);
+  }
 }
 
 void SemaSummarizer::ActOnStartOfSourceFile() {
@@ -221,10 +191,10 @@ void SemaSummarizer::ActOnEndOfSourceFile() {
 }
 
 void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
-  FunctionSummary Summary = TheSummaryManager->SummarizeFunctionBody(FD);
+  TheSummaryManager->SummarizeFunctionBody(FD);
 
   if(TheSummaryConsumer)
-    TheSummaryConsumer->ProcessFunctionSummary(Summary);
+    TheSummaryConsumer->ProcessFunctionSummary(*TheSummaryManager->GetSummary(FD));
 }
 
 } // namespace clang
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Sema/SummaryAttribute.cpp
index 4affec7b4ffb7..953cc38b2e7a1 100644
--- a/clang/lib/Sema/SummaryAttribute.cpp
+++ b/clang/lib/Sema/SummaryAttribute.cpp
@@ -1,19 +1,32 @@
 #include "clang/Sema/SummaryAttribute.h"
+#include "clang/Sema/SemaSummarizer.h"
 
 namespace clang {
-std::string SummaryAttributeDescription::serialize() { return std::string(Serialzed); }
+void NoWriteGlobalDescription::Callback::run(const ast_matchers::MatchFinder::MatchResult &Result) {
+  const auto *Assignment =
+      Result.Nodes.getNodeAs<BinaryOperator>("assignment");
+  if (!Assignment)
+    return;
 
-std::optional<SummaryAttribute> SummaryAttributeDescription::parse(std::string_view input) {
-  if(input == Serialzed)
-    return Attr;
-
-  return std::nullopt;
+  WriteGlobal = true;
 }
 
-std::optional<SummaryAttribute> SummaryAttributeDescription::infer(const FunctionDecl *FD) {
-  if (predicate(FD))
-    return Attr;
+bool NoWriteGlobalDescription::infer(const FunctionDecl *FD) const {
+  using namespace ast_matchers;
+  MatchFinder Finder;
+  Callback CB;
+
+  Finder.addMatcher(
+      functionDecl(forEachDescendant(
+          binaryOperator(isAssignmentOperator(),
+                         hasLHS(declRefExpr(to(varDecl(hasGlobalStorage())))))
+              .bind("assignment"))),
+      &CB);
+  Finder.match(*FD, FD->getASTContext());
+  return !CB.WriteGlobal;
+}
 
-  return std::nullopt;
+bool NoWriteGlobalDescription::merge(const FunctionSummary &Summary) const {
+  return Summary.getFunctionAttrs().count(this);
 }
 } // namespace clang
\ No newline at end of file

>From 4964c96b88d0a1a1b6b251a0489b2e82ceb60ebe Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 12 Jun 2025 01:04:13 +0200
Subject: [PATCH 10/28] [clang][Summary] only keep one constructor for
 `FunctionSummary`

---
 clang/include/clang/Sema/SemaSummarizer.h   | 27 ++++---
 clang/include/clang/Sema/SummaryAttribute.h | 16 ++--
 clang/lib/Sema/SemaSummarizer.cpp           | 87 ++++++++++-----------
 clang/lib/Sema/SummaryAttribute.cpp         |  8 +-
 4 files changed, 73 insertions(+), 65 deletions(-)

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 42f668009d2f2..7fea668bae694 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -9,38 +9,45 @@
 namespace clang {
 class FunctionSummary {
   SmallVector<char> ID;
-  std::set<const SummaryAttribute *> FunctionAttrs;
+  std::set<const SummaryAttribute *> Attrs;
   std::set<SmallVector<char>> Calls;
 
 public:
-  FunctionSummary(SmallVector<char> ID, std::set<const SummaryAttribute *> FunctionAttrs, std::set<SmallVector<char>> Calls);
-  FunctionSummary(const clang::FunctionDecl *FD);
+  FunctionSummary(SmallVector<char> ID,
+                  std::set<const SummaryAttribute *> Attrs,
+                  std::set<SmallVector<char>> Calls);
 
   SmallVector<char> getID() const { return ID; }
-  const std::set<const SummaryAttribute *> &getFunctionAttrs() const { return FunctionAttrs; }
+  const std::set<const SummaryAttribute *> &getAttributes() const {
+    return Attrs;
+  }
   const std::set<SmallVector<char>> &getCalls() const { return Calls; }
 
-  void replaceAttributes(std::set<const SummaryAttribute *> Attrs) { FunctionAttrs = std::move(Attrs); }
-  void addAttribute(const SummaryAttribute * Attr) { FunctionAttrs.emplace(Attr); }
+  void replaceAttributes(std::set<const SummaryAttribute *> Attrs) {
+    this->Attrs = std::move(Attrs);
+  }
 
-  void addCall(const clang::FunctionDecl *FD);
+  friend class SummaryManager;
 };
 
 class SummaryManager {
   std::map<SmallVector<char>, const FunctionSummary *> IDToSummary;
   std::vector<std::unique_ptr<FunctionSummary>> FunctionSummaries;
-  
+
   std::map<SummaryAttributeKind, const SummaryAttribute *> KindToAttribute;
   std::vector<std::unique_ptr<SummaryAttribute>> Attributes;
 
-  void SaveSummary(std::unique_ptr<FunctionSummary> Summary);
+  void CreateSummary(SmallVector<char> ID,
+                     std::set<const SummaryAttribute *> Attrs,
+                     std::set<SmallVector<char>> Calls);
   bool ReduceFunctionSummary(FunctionSummary &FunctionSummary);
+
 public:
   SummaryManager();
 
   const FunctionSummary *GetSummary(const FunctionDecl *FD) const;
   void SummarizeFunctionBody(const FunctionDecl *FD);
-  
+
   void SerializeSummary(llvm::json::OStream &, const FunctionSummary &) const;
   void ParseSummaryFromJSON(StringRef path);
 
diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index bfe7ecf84e795..22067da3a4b81 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -17,16 +17,19 @@ class SummaryAttribute {
   std::string_view Serialzed;
 
 public:
-  SummaryAttribute(SummaryAttributeKind Attr, const char *Str) : Kind(Attr), Serialzed(Str) {}
+  SummaryAttribute(SummaryAttributeKind Attr, const char *Str)
+      : Kind(Attr), Serialzed(Str) {}
   virtual ~SummaryAttribute() = default;
-  
+
   SummaryAttributeKind getKind() { return Kind; }
 
   virtual bool infer(const FunctionDecl *FD) const = 0;
   virtual bool merge(const FunctionSummary &Summary) const = 0;
 
   virtual std::string serialize() const { return std::string(Serialzed); };
-  virtual bool parse(std::string_view input) const { return input == Serialzed; };
+  virtual bool parse(std::string_view input) const {
+    return input == Serialzed;
+  };
 };
 
 class NoWriteGlobalDescription : public SummaryAttribute {
@@ -34,13 +37,14 @@ class NoWriteGlobalDescription : public SummaryAttribute {
   public:
     bool WriteGlobal = false;
 
-    void run(const ast_matchers::MatchFinder::MatchResult &Result) override final;
+    void
+    run(const ast_matchers::MatchFinder::MatchResult &Result) override final;
   };
 
 public:
   NoWriteGlobalDescription()
-  : SummaryAttribute(NO_WRITE_GLOBAL, "no_write_global") {}
-  
+      : SummaryAttribute(NO_WRITE_GLOBAL, "no_write_global") {}
+
   bool infer(const FunctionDecl *FD) const override final;
   bool merge(const FunctionSummary &Summary) const override final;
 };
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 97b2d50bd7602..811c95028abb0 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -9,10 +9,14 @@
 
 namespace clang {
 namespace {
-class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
-  FunctionSummary *Summary;
+SmallVector<char> GetUSR(const FunctionDecl *FD) {
+  SmallVector<char> USR;
+  index::generateUSRForDecl(FD, USR);
+  return USR;
+}
 
-  CallCollector(FunctionSummary &Summary) : Summary(&Summary) {}
+class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
+  std::set<SmallVector<char>> Calls;
 
   virtual void
   run(const ast_matchers::MatchFinder::MatchResult &Result) override {
@@ -21,78 +25,70 @@ class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
       return;
 
     const auto *Callee = llvm::dyn_cast<FunctionDecl>(Call->getCalleeDecl());
-    Summary->addCall(Callee);
+    Calls.emplace(GetUSR(Callee));
   }
 
 public:
-  static void CollectCalledFunctions(const FunctionDecl *FD,
-                                     FunctionSummary &Summary) {
+  std::set<SmallVector<char>> collect(const FunctionDecl *FD) {
     using namespace ast_matchers;
     MatchFinder Finder;
-    CallCollector CC(Summary);
 
     Finder.addMatcher(functionDecl(forEachDescendant(callExpr().bind("call"))),
-                      &CC);
+                      this);
     Finder.match(*FD, FD->getASTContext());
+
+    return Calls;
   }
 };
-
-SmallVector<char> GetUSR(const FunctionDecl *FD) {
-  SmallVector<char> USR;
-  index::generateUSRForDecl(FD, USR);
-  return USR;
-}
 } // namespace
 
-void FunctionSummary::addCall(const clang::FunctionDecl *FD) {
-  Calls.emplace(GetUSR(FD));
-}
-
-FunctionSummary::FunctionSummary(SmallVector<char> ID, std::set<const SummaryAttribute *> FunctionAttrs, std::set<SmallVector<char>> Calls) :
-  ID(std::move(ID)), FunctionAttrs(std::move(FunctionAttrs)), Calls(std::move(Calls)) {}
-
-FunctionSummary::FunctionSummary(const clang::FunctionDecl *FD) : ID(GetUSR(FD)) {}
+FunctionSummary::FunctionSummary(
+    SmallVector<char> ID, std::set<const SummaryAttribute *> FunctionAttrs,
+    std::set<SmallVector<char>> Calls)
+    : ID(std::move(ID)), Attrs(std::move(FunctionAttrs)),
+      Calls(std::move(Calls)) {}
 
 SummaryManager::SummaryManager() {
   Attributes.emplace_back(std::make_unique<NoWriteGlobalDescription>());
 
-  for(auto &&Attr : Attributes) {
-    assert(KindToAttribute.count(Attr->getKind()) == 0 && "Attr already registered");
+  for (auto &&Attr : Attributes) {
+    assert(KindToAttribute.count(Attr->getKind()) == 0 &&
+           "Attr already registered");
     KindToAttribute[Attr->getKind()] = Attr.get();
   }
 }
 
-void SummaryManager::SaveSummary(std::unique_ptr<FunctionSummary> Summary) {
+void SummaryManager::CreateSummary(SmallVector<char> ID,
+                                   std::set<const SummaryAttribute *> Attrs,
+                                   std::set<SmallVector<char>> Calls) {
+  auto Summary = std::make_unique<FunctionSummary>(
+      std::move(ID), std::move(Attrs), std::move(Calls));
   auto *SummaryPtr = FunctionSummaries.emplace_back(std::move(Summary)).get();
   IDToSummary[SummaryPtr->getID()] = SummaryPtr;
 }
 
-const FunctionSummary *SummaryManager::GetSummary(const FunctionDecl *FD) const { 
+const FunctionSummary *
+SummaryManager::GetSummary(const FunctionDecl *FD) const {
   auto USR = GetUSR(FD);
-  if(!IDToSummary.count(USR))
-    return nullptr;
-
-  return IDToSummary.at(USR);
+  return IDToSummary.count(USR) ? IDToSummary.at(USR) : nullptr;
 }
 
 void SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
-  auto Summary = std::make_unique<FunctionSummary>(FD);
-  CallCollector::CollectCalledFunctions(FD, *Summary);
-
+  std::set<const SummaryAttribute *> Attrs;
   for (auto &&Attr : Attributes) {
     if (Attr->infer(FD))
-      Summary->addAttribute(Attr.get());
+      Attrs.emplace(Attr.get());
   }
 
-  SaveSummary(std::move(Summary));
+  CreateSummary(GetUSR(FD), std::move(Attrs), CallCollector().collect(FD));
 }
 
 void SummaryManager::SerializeSummary(llvm::json::OStream &JOS, const FunctionSummary &Summary) const {
   JOS.object([&]{
     JOS.attribute("id", llvm::json::Value(Summary.getID()));
-    JOS.attributeObject("attrs", [&]{
-      JOS.attributeArray("function", [&]{
-        for(auto &&Attr : Summary.getFunctionAttrs()) {
+    JOS.attributeObject("attrs", [&] {
+      JOS.attributeArray("function", [&] {
+        for (auto &&Attr : Summary.getAttributes()) {
           JOS.value(llvm::json::Value(Attr->serialize()));
         }
       });
@@ -124,8 +120,8 @@ void SummaryManager::ParseSummaryFromJSON(StringRef path) {
     std::set<const SummaryAttribute *> FunctionAttrs;
     llvm::json::Array *FunctionAttributes = Summary->getObject("attrs")->getArray("function");
     for(auto attrIt = FunctionAttributes->begin(); attrIt != FunctionAttributes->end(); ++attrIt) {
-      for(auto &&Attr : Attributes) {
-        if(Attr->parse(*attrIt->getAsString()))
+      for (auto &&Attr : Attributes) {
+        if (Attr->parse(*attrIt->getAsString()))
           FunctionAttrs.emplace(Attr.get());
       }
     }
@@ -136,8 +132,8 @@ void SummaryManager::ParseSummaryFromJSON(StringRef path) {
       auto *Obj = callIt->getAsObject();
       Calls.emplace(SmallString<128>(*Obj->getString("id")));
     }
-    
-    SaveSummary(std::make_unique<FunctionSummary>(std::move(ID), std::move(FunctionAttrs), std::move(Calls)));
+
+    CreateSummary(std::move(ID), std::move(FunctionAttrs), std::move(Calls));
   }
 }
 
@@ -156,12 +152,12 @@ bool SummaryManager::ReduceFunctionSummary(FunctionSummary &Function) {
 
     const FunctionSummary *callSummary = IDToSummary[call];
 
-    for (auto &&Attr : Function.getFunctionAttrs()) {
+    for (auto &&Attr : Function.getAttributes()) {
       if (Attr->merge(*callSummary))
         reducedAttrs.emplace(Attr);
     }
 
-    if (reducedAttrs != Function.getFunctionAttrs()) {
+    if (reducedAttrs != Function.getAttributes()) {
       Function.replaceAttributes(std::move(reducedAttrs));
       changed = true;
     }
@@ -194,7 +190,8 @@ void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
   TheSummaryManager->SummarizeFunctionBody(FD);
 
   if(TheSummaryConsumer)
-    TheSummaryConsumer->ProcessFunctionSummary(*TheSummaryManager->GetSummary(FD));
+    TheSummaryConsumer->ProcessFunctionSummary(
+        *TheSummaryManager->GetSummary(FD));
 }
 
 } // namespace clang
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Sema/SummaryAttribute.cpp
index 953cc38b2e7a1..c1611ef90fae5 100644
--- a/clang/lib/Sema/SummaryAttribute.cpp
+++ b/clang/lib/Sema/SummaryAttribute.cpp
@@ -2,9 +2,9 @@
 #include "clang/Sema/SemaSummarizer.h"
 
 namespace clang {
-void NoWriteGlobalDescription::Callback::run(const ast_matchers::MatchFinder::MatchResult &Result) {
-  const auto *Assignment =
-      Result.Nodes.getNodeAs<BinaryOperator>("assignment");
+void NoWriteGlobalDescription::Callback::run(
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  const auto *Assignment = Result.Nodes.getNodeAs<BinaryOperator>("assignment");
   if (!Assignment)
     return;
 
@@ -27,6 +27,6 @@ bool NoWriteGlobalDescription::infer(const FunctionDecl *FD) const {
 }
 
 bool NoWriteGlobalDescription::merge(const FunctionSummary &Summary) const {
-  return Summary.getFunctionAttrs().count(this);
+  return Summary.getAttributes().count(this);
 }
 } // namespace clang
\ No newline at end of file

>From d8c26d3d7a6bcf989748bcde25f6ef46c93f43eb Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 12 Jun 2025 01:13:23 +0200
Subject: [PATCH 11/28] [clang][Summary] the summary manager shouldn't be
 reading the JSON file

---
 clang/include/clang/Sema/SemaSummarizer.h |  2 +-
 clang/lib/Frontend/FrontendAction.cpp     | 15 +++++++++++--
 clang/lib/Sema/SemaSummarizer.cpp         | 26 +++++++----------------
 3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 7fea668bae694..2c58591350b8e 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -49,7 +49,7 @@ class SummaryManager {
   void SummarizeFunctionBody(const FunctionDecl *FD);
 
   void SerializeSummary(llvm::json::OStream &, const FunctionSummary &) const;
-  void ParseSummaryFromJSON(StringRef path);
+  void ParseSummaryFromJSON(const llvm::json::Array &Summary);
 
   void ReduceSummaries();
 
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 7af4a79f83eec..b8732e58e7ffd 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -47,7 +47,9 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
+#include <fstream>
 #include <memory>
+#include <sstream>
 #include <system_error>
 using namespace clang;
 
@@ -981,8 +983,17 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
       for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC),
                                          DirEnd;
            Dir != DirEnd && !EC; Dir.increment(EC)) {
-        if (llvm::sys::path::extension(Dir->path()) == ".json")
-          CI.getSummaryManager().ParseSummaryFromJSON(Dir->path());
+        if (llvm::sys::path::extension(Dir->path()) == ".json") {
+          std::ifstream t(Dir->path().str());
+          std::stringstream buffer;
+          buffer << t.rdbuf();
+
+          auto JSON = llvm::json::parse(buffer.str());
+          if (!JSON)
+            continue;
+
+          CI.getSummaryManager().ParseSummaryFromJSON(*JSON->getAsArray());
+        }
       }
 
       // FIXME: debug only, remove later
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 811c95028abb0..5cd25fd563b90 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -1,11 +1,9 @@
 #include "clang/Sema/SemaSummarizer.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Index/USRGeneration.h"
-#include "clang/Sema/SummaryConsumer.h"
 #include "clang/Sema/SummaryAttribute.h"
+#include "clang/Sema/SummaryConsumer.h"
 #include <set>
-#include <fstream>
-#include <sstream>
 
 namespace clang {
 namespace {
@@ -103,22 +101,14 @@ void SummaryManager::SerializeSummary(llvm::json::OStream &JOS, const FunctionSu
   });
 }
 
-void SummaryManager::ParseSummaryFromJSON(StringRef path) {
-  std::ifstream t(path.str());
-  std::stringstream buffer;
-  buffer << t.rdbuf();
-
-  auto JSON = llvm::json::parse(buffer.str());
-  if (!JSON)
-    return;
-
-  llvm::json::Array *Summaries = JSON->getAsArray();
-  for(auto it = Summaries->begin(); it != Summaries->end(); ++it) {
-    llvm::json::Object *Summary = it->getAsObject();
+void SummaryManager::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
+  for (auto it = Summary.begin(); it != Summary.end(); ++it) {
+    const llvm::json::Object *FunctionSummary = it->getAsObject();
 
-    SmallString<128> ID(*Summary->getString("id"));
+    SmallString<128> ID(*FunctionSummary->getString("id"));
     std::set<const SummaryAttribute *> FunctionAttrs;
-    llvm::json::Array *FunctionAttributes = Summary->getObject("attrs")->getArray("function");
+    const llvm::json::Array *FunctionAttributes =
+        FunctionSummary->getObject("attrs")->getArray("function");
     for(auto attrIt = FunctionAttributes->begin(); attrIt != FunctionAttributes->end(); ++attrIt) {
       for (auto &&Attr : Attributes) {
         if (Attr->parse(*attrIt->getAsString()))
@@ -127,7 +117,7 @@ void SummaryManager::ParseSummaryFromJSON(StringRef path) {
     }
 
     std::set<SmallVector<char>> Calls;
-    llvm::json::Array *CallEntries = Summary->getArray("calls");
+    const llvm::json::Array *CallEntries = FunctionSummary->getArray("calls");
     for(auto callIt = CallEntries->begin(); callIt != CallEntries->end(); ++callIt) {
       auto *Obj = callIt->getAsObject();
       Calls.emplace(SmallString<128>(*Obj->getString("id")));

>From b5465c15d2e8bf8d9667894a775b96cdaa99c768 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 12 Jun 2025 01:17:07 +0200
Subject: [PATCH 12/28] [clang][Summary] the summary manager shouldn't contain
 the JSON summary consumer logic

---
 clang/include/clang/Sema/SemaSummarizer.h |  7 -------
 clang/lib/Frontend/FrontendAction.cpp     | 14 --------------
 clang/lib/Sema/SemaSummarizer.cpp         | 20 --------------------
 clang/lib/Sema/SummaryConsumer.cpp        | 16 +++++++++++++++-
 4 files changed, 15 insertions(+), 42 deletions(-)

diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SemaSummarizer.h
index 2c58591350b8e..7e0c5990e5de1 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SemaSummarizer.h
@@ -48,15 +48,8 @@ class SummaryManager {
   const FunctionSummary *GetSummary(const FunctionDecl *FD) const;
   void SummarizeFunctionBody(const FunctionDecl *FD);
 
-  void SerializeSummary(llvm::json::OStream &, const FunctionSummary &) const;
   void ParseSummaryFromJSON(const llvm::json::Array &Summary);
-
   void ReduceSummaries();
-
-  // FIXME: debug only, remove later
-  const std::vector<std::unique_ptr<FunctionSummary>> &getSummaries() {
-    return FunctionSummaries;
-  }
 };
 
 // FIXME: Is this class needed?
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index b8732e58e7ffd..dfbc3e0d14e91 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -996,21 +996,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
         }
       }
 
-      // FIXME: debug only, remove later
-      for (auto &&S : CI.getSummaryManager().getSummaries()) {
-        llvm::json::OStream Out(llvm::errs());
-        CI.getSummaryManager().SerializeSummary(Out, *S);
-      }
-      llvm::errs() << '\n';
-
       CI.getSummaryManager().ReduceSummaries();
-
-      // FIXME: debug only, remove later
-      for (auto &&S : CI.getSummaryManager().getSummaries()) {
-        llvm::json::OStream Out(llvm::errs());
-        CI.getSummaryManager().SerializeSummary(Out, *S);
-      }
-      llvm::errs() << '\n';
     }
   }
 
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 5cd25fd563b90..615df8e78a90b 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -81,26 +81,6 @@ void SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
   CreateSummary(GetUSR(FD), std::move(Attrs), CallCollector().collect(FD));
 }
 
-void SummaryManager::SerializeSummary(llvm::json::OStream &JOS, const FunctionSummary &Summary) const {
-  JOS.object([&]{
-    JOS.attribute("id", llvm::json::Value(Summary.getID()));
-    JOS.attributeObject("attrs", [&] {
-      JOS.attributeArray("function", [&] {
-        for (auto &&Attr : Summary.getAttributes()) {
-          JOS.value(llvm::json::Value(Attr->serialize()));
-        }
-      });
-    });
-    JOS.attributeArray("calls", [&]{
-      for(auto &&Call : Summary.getCalls()) {
-        JOS.object([&]{
-          JOS.attribute("id", llvm::json::Value(Call));
-        });
-      }
-    });
-  });
-}
-
 void SummaryManager::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
   for (auto it = Summary.begin(); it != Summary.end(); ++it) {
     const llvm::json::Object *FunctionSummary = it->getAsObject();
diff --git a/clang/lib/Sema/SummaryConsumer.cpp b/clang/lib/Sema/SummaryConsumer.cpp
index 37646c1e07a7f..b10bc827f94ab 100644
--- a/clang/lib/Sema/SummaryConsumer.cpp
+++ b/clang/lib/Sema/SummaryConsumer.cpp
@@ -3,6 +3,20 @@
 
 namespace clang {
 void JSONPrintingSummaryConsumer::ProcessFunctionSummary(const FunctionSummary &Summary) {
-  TheSummaryManager->SerializeSummary(JOS, Summary);
+  JOS.object([&] {
+    JOS.attribute("id", llvm::json::Value(Summary.getID()));
+    JOS.attributeObject("attrs", [&] {
+      JOS.attributeArray("function", [&] {
+        for (auto &&Attr : Summary.getAttributes()) {
+          JOS.value(llvm::json::Value(Attr->serialize()));
+        }
+      });
+    });
+    JOS.attributeArray("calls", [&] {
+      for (auto &&Call : Summary.getCalls()) {
+        JOS.object([&] { JOS.attribute("id", llvm::json::Value(Call)); });
+      }
+    });
+  });
 }
 } // namespace clang
\ No newline at end of file

>From 1754b30c1a54261223b827da001ba078815b79ea Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 12 Jun 2025 01:25:59 +0200
Subject: [PATCH 13/28] [clang][Summary] rename description to attr

---
 clang/include/clang/Sema/SummaryAttribute.h | 5 ++---
 clang/lib/Sema/SemaSummarizer.cpp           | 2 +-
 clang/lib/Sema/SummaryAttribute.cpp         | 6 +++---
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index 22067da3a4b81..759710fb052e6 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -32,7 +32,7 @@ class SummaryAttribute {
   };
 };
 
-class NoWriteGlobalDescription : public SummaryAttribute {
+class NoWriteGlobalAttr : public SummaryAttribute {
   class Callback : public ast_matchers::MatchFinder::MatchCallback {
   public:
     bool WriteGlobal = false;
@@ -42,8 +42,7 @@ class NoWriteGlobalDescription : public SummaryAttribute {
   };
 
 public:
-  NoWriteGlobalDescription()
-      : SummaryAttribute(NO_WRITE_GLOBAL, "no_write_global") {}
+  NoWriteGlobalAttr() : SummaryAttribute(NO_WRITE_GLOBAL, "no_write_global") {}
 
   bool infer(const FunctionDecl *FD) const override final;
   bool merge(const FunctionSummary &Summary) const override final;
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 615df8e78a90b..63091b6f7fefc 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -47,7 +47,7 @@ FunctionSummary::FunctionSummary(
       Calls(std::move(Calls)) {}
 
 SummaryManager::SummaryManager() {
-  Attributes.emplace_back(std::make_unique<NoWriteGlobalDescription>());
+  Attributes.emplace_back(std::make_unique<NoWriteGlobalAttr>());
 
   for (auto &&Attr : Attributes) {
     assert(KindToAttribute.count(Attr->getKind()) == 0 &&
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Sema/SummaryAttribute.cpp
index c1611ef90fae5..48fda7077f4a3 100644
--- a/clang/lib/Sema/SummaryAttribute.cpp
+++ b/clang/lib/Sema/SummaryAttribute.cpp
@@ -2,7 +2,7 @@
 #include "clang/Sema/SemaSummarizer.h"
 
 namespace clang {
-void NoWriteGlobalDescription::Callback::run(
+void NoWriteGlobalAttr::Callback::run(
     const ast_matchers::MatchFinder::MatchResult &Result) {
   const auto *Assignment = Result.Nodes.getNodeAs<BinaryOperator>("assignment");
   if (!Assignment)
@@ -11,7 +11,7 @@ void NoWriteGlobalDescription::Callback::run(
   WriteGlobal = true;
 }
 
-bool NoWriteGlobalDescription::infer(const FunctionDecl *FD) const {
+bool NoWriteGlobalAttr::infer(const FunctionDecl *FD) const {
   using namespace ast_matchers;
   MatchFinder Finder;
   Callback CB;
@@ -26,7 +26,7 @@ bool NoWriteGlobalDescription::infer(const FunctionDecl *FD) const {
   return !CB.WriteGlobal;
 }
 
-bool NoWriteGlobalDescription::merge(const FunctionSummary &Summary) const {
+bool NoWriteGlobalAttr::merge(const FunctionSummary &Summary) const {
   return Summary.getAttributes().count(this);
 }
 } // namespace clang
\ No newline at end of file

>From 7e27c32c9a0c03a0fc995bb3710aac61494219ad Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Fri, 13 Jun 2025 00:21:50 +0200
Subject: [PATCH 14/28] [clang][Summary] more flexible merge logic

---
 clang/include/clang/Sema/SummaryAttribute.h | 6 ++++--
 clang/lib/Sema/SemaSummarizer.cpp           | 7 ++++---
 clang/lib/Sema/SummaryAttribute.cpp         | 6 ++++--
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index 759710fb052e6..0014a9878bacd 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -24,7 +24,8 @@ class SummaryAttribute {
   SummaryAttributeKind getKind() { return Kind; }
 
   virtual bool infer(const FunctionDecl *FD) const = 0;
-  virtual bool merge(const FunctionSummary &Summary) const = 0;
+  virtual bool merge(const FunctionSummary &Caller,
+                     const FunctionSummary &Callee) const = 0;
 
   virtual std::string serialize() const { return std::string(Serialzed); };
   virtual bool parse(std::string_view input) const {
@@ -45,7 +46,8 @@ class NoWriteGlobalAttr : public SummaryAttribute {
   NoWriteGlobalAttr() : SummaryAttribute(NO_WRITE_GLOBAL, "no_write_global") {}
 
   bool infer(const FunctionDecl *FD) const override final;
-  bool merge(const FunctionSummary &Summary) const override final;
+  bool merge(const FunctionSummary &Caller,
+             const FunctionSummary &Callee) const override final;
 };
 } // namespace clang
 
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SemaSummarizer.cpp
index 63091b6f7fefc..3b056fc53f8c9 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SemaSummarizer.cpp
@@ -73,6 +73,7 @@ SummaryManager::GetSummary(const FunctionDecl *FD) const {
 
 void SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
   std::set<const SummaryAttribute *> Attrs;
+
   for (auto &&Attr : Attributes) {
     if (Attr->infer(FD))
       Attrs.emplace(Attr.get());
@@ -122,9 +123,9 @@ bool SummaryManager::ReduceFunctionSummary(FunctionSummary &Function) {
 
     const FunctionSummary *callSummary = IDToSummary[call];
 
-    for (auto &&Attr : Function.getAttributes()) {
-      if (Attr->merge(*callSummary))
-        reducedAttrs.emplace(Attr);
+    for (auto &&Attr : Attributes) {
+      if (Attr->merge(Function, *callSummary))
+        reducedAttrs.emplace(Attr.get());
     }
 
     if (reducedAttrs != Function.getAttributes()) {
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Sema/SummaryAttribute.cpp
index 48fda7077f4a3..6f141dde68e52 100644
--- a/clang/lib/Sema/SummaryAttribute.cpp
+++ b/clang/lib/Sema/SummaryAttribute.cpp
@@ -26,7 +26,9 @@ bool NoWriteGlobalAttr::infer(const FunctionDecl *FD) const {
   return !CB.WriteGlobal;
 }
 
-bool NoWriteGlobalAttr::merge(const FunctionSummary &Summary) const {
-  return Summary.getAttributes().count(this);
+bool NoWriteGlobalAttr::merge(const FunctionSummary &Caller,
+                              const FunctionSummary &Callee) const {
+  return Caller.getAttributes().count(this) &&
+         Callee.getAttributes().count(this);
 }
 } // namespace clang
\ No newline at end of file

>From 4f8acb909effe739523a7342e5bf6dbb0ac75353 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 00:02:10 +0200
Subject: [PATCH 15/28] [clang][Summary] refactor summaries in the compiler
 instance and sema

---
 .../include/clang/Frontend/CompilerInstance.h | 41 ++++++++++---------
 clang/include/clang/Sema/Sema.h               |  8 ++--
 clang/include/clang/Sema/SummaryConsumer.h    | 27 ++++++------
 .../{SemaSummarizer.h => SummaryContext.h}    | 27 +++---------
 clang/lib/Frontend/CompilerInstance.cpp       | 19 +++++----
 clang/lib/Frontend/FrontendAction.cpp         | 14 +++----
 clang/lib/Sema/CMakeLists.txt                 |  2 +-
 clang/lib/Sema/Sema.cpp                       | 21 +++++-----
 clang/lib/Sema/SemaDecl.cpp                   |  8 ++--
 clang/lib/Sema/SummaryAttribute.cpp           |  2 +-
 clang/lib/Sema/SummaryConsumer.cpp            |  2 +-
 ...{SemaSummarizer.cpp => SummaryContext.cpp} | 35 ++++------------
 12 files changed, 89 insertions(+), 117 deletions(-)
 rename clang/include/clang/Sema/{SemaSummarizer.h => SummaryContext.h} (67%)
 rename clang/lib/Sema/{SemaSummarizer.cpp => SummaryContext.cpp} (82%)

diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index f8f13bbc998d9..b107f15af9563 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -19,6 +19,7 @@
 #include "clang/Lex/DependencyDirectivesScanner.h"
 #include "clang/Lex/HeaderSearchOptions.h"
 #include "clang/Lex/ModuleLoader.h"
+#include "clang/Sema/SummaryContext.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -48,6 +49,7 @@ class ModuleFile;
 }
 
 class CodeCompleteConsumer;
+class SummaryContext;
 class SummaryConsumer;
 class DiagnosticsEngine;
 class DiagnosticConsumer;
@@ -57,7 +59,6 @@ class Module;
 class ModuleCache;
 class Preprocessor;
 class Sema;
-class SummaryManager;
 class SourceManager;
 class TargetInfo;
 enum class DisableValidationForModuleKind;
@@ -125,9 +126,12 @@ class CompilerInstance : public ModuleLoader {
 
   /// The summary consumer.
   std::unique_ptr<SummaryConsumer> TheSummaryConsumer;
-  
-  /// The summary manager object.
-  std::unique_ptr<SummaryManager> TheSummaryManager;
+
+  /// The summary context.
+  std::unique_ptr<SummaryContext> SummaryCtx;
+
+  /// The summary output file.
+  std::unique_ptr<llvm::raw_fd_ostream> SummaryOS;
 
   /// The semantic analysis object.
   std::unique_ptr<Sema> TheSema;
@@ -524,15 +528,6 @@ class CompilerInstance : public ModuleLoader {
   /// setASTContext - Replace the current AST context.
   void setASTContext(ASTContext *Value);
 
-  bool hasSummaryManager() {
-    return TheSummaryManager != nullptr;
-  }
-
-  SummaryManager &getSummaryManager() {
-    assert(TheSummaryManager && "Compiler instance has no summary manager!");
-    return *TheSummaryManager;
-  }
-
   /// Replace the current Sema; the compiler instance takes ownership
   /// of S.
   void setSema(Sema *S);
@@ -624,10 +619,23 @@ class CompilerInstance : public ModuleLoader {
     return *CompletionConsumer;
   }
 
+  /// setCodeCompletionConsumer - Replace the current code completion consumer;
+  /// the compiler instance takes ownership of \p Value.
+  void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
+
   /// @}
   /// @name Summary
   /// @{
 
+  bool hasSummaryContext() { return (bool)SummaryCtx; }
+
+  SummaryContext &getSummaryContext() {
+    assert(SummaryCtx && "Compiler instance has no summary context!");
+    return *SummaryCtx;
+  }
+
+  void createSummaryContext() { SummaryCtx.reset(new SummaryContext()); }
+
   bool hasSummaryConsumer() const { return (bool)TheSummaryConsumer; }
 
   SummaryConsumer &getSummaryConsumer() const {
@@ -636,9 +644,7 @@ class CompilerInstance : public ModuleLoader {
     return *TheSummaryConsumer;
   }
 
-  /// setCodeCompletionConsumer - Replace the current code completion consumer;
-  /// the compiler instance takes ownership of \p Value.
-  void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
+  void createSummaryConsumer();
 
   /// @}
   /// @name Frontend timer
@@ -765,9 +771,6 @@ class CompilerInstance : public ModuleLoader {
       Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column,
       const CodeCompleteOptions &Opts, raw_ostream &OS);
 
-  void createSummaryConsumer();
-  void createSummaryManager();
-
   /// Create the Sema object to be used for parsing.
   void createSema(TranslationUnitKind TUKind,
                   CodeCompleteConsumer *CompletionConsumer,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b36fce47fb792..1a4d2e99685e0 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -125,7 +125,7 @@ class CXXBasePath;
 class CXXBasePaths;
 class CXXFieldCollector;
 class CodeCompleteConsumer;
-class SummaryManager;
+class SummaryContext;
 class SummaryConsumer;
 enum class ComparisonCategoryType : unsigned char;
 class ConstraintSatisfaction;
@@ -161,7 +161,6 @@ class SemaARM;
 class SemaAVR;
 class SemaBPF;
 class SemaCodeCompletion;
-class SemaSummarizer;
 class SemaCUDA;
 class SemaDirectX;
 class SemaHLSL;
@@ -887,7 +886,7 @@ class Sema final : public SemaBase {
   Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
        TranslationUnitKind TUKind = TU_Complete,
        CodeCompleteConsumer *CompletionConsumer = nullptr,
-       SummaryManager *SummaryManager = nullptr,
+       SummaryContext *SummaryCtx = nullptr,
        SummaryConsumer *SummaryConsumer = nullptr);
   ~Sema();
 
@@ -1265,6 +1264,8 @@ class Sema final : public SemaBase {
   DiagnosticsEngine &Diags;
   SourceManager &SourceMgr;
   api_notes::APINotesManager APINotes;
+  SummaryContext *SummaryCtx;
+  SummaryConsumer *SummaryCnsmr;
 
   /// A RAII object to enter scope of a compound statement.
   class CompoundScopeRAII {
@@ -1569,7 +1570,6 @@ class Sema final : public SemaBase {
   std::unique_ptr<SemaAVR> AVRPtr;
   std::unique_ptr<SemaBPF> BPFPtr;
   std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
-  std::unique_ptr<SemaSummarizer> SummarizerPtr;
   std::unique_ptr<SemaCUDA> CUDAPtr;
   std::unique_ptr<SemaDirectX> DirectXPtr;
   std::unique_ptr<SemaHLSL> HLSLPtr;
diff --git a/clang/include/clang/Sema/SummaryConsumer.h b/clang/include/clang/Sema/SummaryConsumer.h
index 85c48b3c1b939..f8844ffb64e21 100644
--- a/clang/include/clang/Sema/SummaryConsumer.h
+++ b/clang/include/clang/Sema/SummaryConsumer.h
@@ -5,36 +5,37 @@
 #include "llvm/Support/JSON.h"
 namespace clang {
 class FunctionSummary;
-class SummaryManager;
+class SummaryContext;
 
 class SummaryConsumer {
 protected:
-    const SummaryManager *TheSummaryManager;
+  const SummaryContext *SummaryCtx;
 
 public:
-    SummaryConsumer(const SummaryManager &SummaryManager) : TheSummaryManager(&SummaryManager) {}
-    virtual ~SummaryConsumer() = default;
+  SummaryConsumer(const SummaryContext &SummaryCtx) : SummaryCtx(&SummaryCtx) {}
+  virtual ~SummaryConsumer() = default;
 
-    virtual void ProcessStartOfSourceFile() {};
-    virtual void ProcessFunctionSummary(const FunctionSummary&) {};
-    virtual void ProcessEndOfSourceFile() {};
+  virtual void ProcessStartOfSourceFile(){};
+  virtual void ProcessFunctionSummary(const FunctionSummary &){};
+  virtual void ProcessEndOfSourceFile(){};
 };
 
 class PrintingSummaryConsumer : public SummaryConsumer {
 public:
-    PrintingSummaryConsumer(const SummaryManager &SummaryManager, raw_ostream &OS)
-      : SummaryConsumer(SummaryManager) {}
+  PrintingSummaryConsumer(const SummaryContext &SummaryCtx, raw_ostream &OS)
+      : SummaryConsumer(SummaryCtx) {}
 };
 
 class JSONPrintingSummaryConsumer : public PrintingSummaryConsumer {
     llvm::json::OStream JOS;
 
 public:
-    JSONPrintingSummaryConsumer(const SummaryManager &SummaryManager, raw_ostream &OS) : PrintingSummaryConsumer(SummaryManager, OS), JOS(OS, 2) {}
+  JSONPrintingSummaryConsumer(const SummaryContext &SummaryCtx, raw_ostream &OS)
+      : PrintingSummaryConsumer(SummaryCtx, OS), JOS(OS, 2) {}
 
-    void ProcessStartOfSourceFile() override { JOS.arrayBegin(); };
-    void ProcessFunctionSummary(const FunctionSummary&) override;
-    void ProcessEndOfSourceFile() override { JOS.arrayEnd(); };
+  void ProcessStartOfSourceFile() override { JOS.arrayBegin(); };
+  void ProcessFunctionSummary(const FunctionSummary &) override;
+  void ProcessEndOfSourceFile() override { JOS.arrayEnd(); };
 };
 } // namespace clang
 
diff --git a/clang/include/clang/Sema/SemaSummarizer.h b/clang/include/clang/Sema/SummaryContext.h
similarity index 67%
rename from clang/include/clang/Sema/SemaSummarizer.h
rename to clang/include/clang/Sema/SummaryContext.h
index 7e0c5990e5de1..67b1162d61763 100644
--- a/clang/include/clang/Sema/SemaSummarizer.h
+++ b/clang/include/clang/Sema/SummaryContext.h
@@ -1,7 +1,6 @@
-#ifndef LLVM_CLANG_SEMA_SEMASUMMARIZER_H
-#define LLVM_CLANG_SEMA_SEMASUMMARIZER_H
+#ifndef LLVM_CLANG_SEMA_SEMASUMMARYCONTEXT_H
+#define LLVM_CLANG_SEMA_SEMASUMMARYCONTEXT_H
 
-#include "clang/Sema/SemaBase.h"
 #include "clang/Sema/SummaryAttribute.h"
 #include "clang/Sema/SummaryConsumer.h"
 #include <set>
@@ -26,11 +25,9 @@ class FunctionSummary {
   void replaceAttributes(std::set<const SummaryAttribute *> Attrs) {
     this->Attrs = std::move(Attrs);
   }
-
-  friend class SummaryManager;
 };
 
-class SummaryManager {
+class SummaryContext {
   std::map<SmallVector<char>, const FunctionSummary *> IDToSummary;
   std::vector<std::unique_ptr<FunctionSummary>> FunctionSummaries;
 
@@ -43,7 +40,7 @@ class SummaryManager {
   bool ReduceFunctionSummary(FunctionSummary &FunctionSummary);
 
 public:
-  SummaryManager();
+  SummaryContext();
 
   const FunctionSummary *GetSummary(const FunctionDecl *FD) const;
   void SummarizeFunctionBody(const FunctionDecl *FD);
@@ -51,20 +48,6 @@ class SummaryManager {
   void ParseSummaryFromJSON(const llvm::json::Array &Summary);
   void ReduceSummaries();
 };
-
-// FIXME: Is this class needed?
-class SemaSummarizer : public SemaBase {
-public:
-  SummaryManager *TheSummaryManager;
-  SummaryConsumer *TheSummaryConsumer;
-
-  SemaSummarizer(Sema &S, SummaryManager &SummaryManager, SummaryConsumer *SummaryConsumer) 
-    : SemaBase(S), TheSummaryManager(&SummaryManager), TheSummaryConsumer(SummaryConsumer) {};
-
-  void ActOnStartOfSourceFile();
-  void ActOnEndOfSourceFile();
-  void SummarizeFunctionBody(const FunctionDecl *FD);
-};
 } // namespace clang
 
-#endif // LLVM_CLANG_SEMA_SEMASUMMARIZE_H
+#endif // LLVM_CLANG_SEMA_SEMASUMMARYCONTEXTH
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index deed94e1f0b42..448d45b0f49db 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -37,7 +37,6 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/ParsedAttr.h"
 #include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaSummarizer.h"
 #include "clang/Sema/SummaryConsumer.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/GlobalModuleIndex.h"
@@ -749,22 +748,24 @@ void CompilerInstance::createSummaryConsumer() {
     return;
 
   std::error_code EC;
-  // FIXME: this being static is a design error
-  static llvm::raw_fd_ostream SummaryOS(SummaryFile, EC, llvm::sys::fs::CD_CreateAlways);
+  SummaryOS.reset(new llvm::raw_fd_ostream(SummaryFile, EC,
+                                           llvm::sys::fs::CD_CreateAlways));
 
-  if(!EC)
-    TheSummaryConsumer.reset(new JSONPrintingSummaryConsumer(getSummaryManager(), SummaryOS));
-}
+  if (EC) {
+    SummaryOS = nullptr;
+    return;
+  }
 
-void CompilerInstance::createSummaryManager() {
-  TheSummaryManager.reset(new SummaryManager());
+  TheSummaryConsumer.reset(
+      new JSONPrintingSummaryConsumer(getSummaryContext(), *SummaryOS));
 }
 
 void CompilerInstance::createSema(TranslationUnitKind TUKind,
                                   CodeCompleteConsumer *CompletionConsumer,
                                   SummaryConsumer *SummaryConsumer) {
   TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
-                         TUKind, CompletionConsumer, hasSummaryManager() ? &getSummaryManager() : nullptr, SummaryConsumer));
+                         TUKind, CompletionConsumer, &getSummaryContext(),
+                         SummaryConsumer));
 
   // Set up API notes.
   TheSema->APINotes.setSwiftVersion(getAPINotesOpts().SwiftVersion);
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index dfbc3e0d14e91..2821327c6a824 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -35,7 +35,7 @@
 #include "clang/Parse/ParseAST.h"
 #include "clang/Sema/HLSLExternalSemaSource.h"
 #include "clang/Sema/MultiplexExternalSemaSource.h"
-#include "clang/Sema/SemaSummarizer.h"
+#include "clang/Sema/SummaryContext.h"
 #include "clang/Serialization/ASTDeserializationListener.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/GlobalModuleIndex.h"
@@ -895,8 +895,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     }
   }
 
-  if(!CI.hasSummaryManager()) {
-    CI.createSummaryManager();
+  if (!CI.hasSummaryContext()) {
+    CI.createSummaryContext();
   }
 
   // Set up embedding for any specified files. Do this before we load any
@@ -992,11 +992,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
           if (!JSON)
             continue;
 
-          CI.getSummaryManager().ParseSummaryFromJSON(*JSON->getAsArray());
+          CI.getSummaryContext().ParseSummaryFromJSON(*JSON->getAsArray());
         }
       }
 
-      CI.getSummaryManager().ReduceSummaries();
+      CI.getSummaryContext().ReduceSummaries();
     }
   }
 
@@ -1371,8 +1371,8 @@ void ASTFrontendAction::ExecuteAction() {
   if (CI.hasCodeCompletionConsumer())
     CompletionConsumer = &CI.getCodeCompletionConsumer();
 
-  if(!CI.hasSummaryManager()) {
-    CI.createSummaryManager();
+  if (!CI.hasSummaryContext()) {
+    CI.createSummaryContext();
   }
   CI.createSummaryConsumer();
 
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index bf8f73dc985db..9d5a593813bd3 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -85,7 +85,6 @@ add_clang_library(clangSema
   SemaStmt.cpp
   SemaStmtAsm.cpp
   SemaStmtAttr.cpp
-  SemaSummarizer.cpp
   SemaSPIRV.cpp
   SemaSYCL.cpp
   SemaSwift.cpp
@@ -101,6 +100,7 @@ add_clang_library(clangSema
   SemaX86.cpp
   SummaryAttribute.cpp
   SummaryConsumer.cpp
+  SummaryContext.cpp
   TypeLocBuilder.cpp
 
   DEPENDS
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 5b3f1a4dca36e..2870871876701 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -64,11 +64,11 @@
 #include "clang/Sema/SemaRISCV.h"
 #include "clang/Sema/SemaSPIRV.h"
 #include "clang/Sema/SemaSYCL.h"
-#include "clang/Sema/SemaSummarizer.h"
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaSystemZ.h"
 #include "clang/Sema/SemaWasm.h"
 #include "clang/Sema/SemaX86.h"
+#include "clang/Sema/SummaryContext.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/Sema/TemplateInstCallback.h"
 #include "clang/Sema/TypoCorrection.h"
@@ -250,12 +250,12 @@ const uint64_t Sema::MaximumAlignment;
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
            TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter,
-           SummaryManager *SummaryManager,
-           SummaryConsumer *SummaryConsumer)
+           SummaryContext *SummaryCtx, SummaryConsumer *SummaryConsumer)
     : SemaBase(*this), CollectStats(false), TUKind(TUKind),
       CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
       Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
       SourceMgr(PP.getSourceManager()), APINotes(SourceMgr, LangOpts),
+      SummaryCtx(SummaryCtx), SummaryCnsmr(SummaryConsumer),
       AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
       LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr),
       OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr),
@@ -266,8 +266,6 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       BPFPtr(std::make_unique<SemaBPF>(*this)),
       CodeCompletionPtr(
           std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
-      SummarizerPtr(SummaryManager ? std::make_unique<SemaSummarizer>(*this, *SummaryManager, SummaryConsumer)
-                                    : nullptr),
       CUDAPtr(std::make_unique<SemaCUDA>(*this)),
       DirectXPtr(std::make_unique<SemaDirectX>(*this)),
       HLSLPtr(std::make_unique<SemaHLSL>(*this)),
@@ -309,6 +307,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
       AccessCheckingSFINAE(false), CurrentInstantiationScope(nullptr),
       InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
       ArgPackSubstIndex(std::nullopt), SatisfactionCache(Context) {
+  assert((!SummaryConsumer || SummaryCtx) &&
+         "summary consumer without a summary context");
   assert(pp.TUKind == TUKind);
   TUScope = nullptr;
 
@@ -1147,9 +1147,9 @@ void Sema::ActOnStartOfTranslationUnit() {
   if (getLangOpts().CPlusPlusModules &&
       getLangOpts().getCompilingModule() == LangOptions::CMK_HeaderUnit)
     HandleStartOfHeaderUnit();
-  
-  if(SummarizerPtr)
-    SummarizerPtr->ActOnStartOfSourceFile();
+
+  if (SummaryCnsmr)
+    SummaryCnsmr->ProcessStartOfSourceFile();
 }
 
 void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
@@ -1225,8 +1225,9 @@ void Sema::ActOnEndOfTranslationUnit() {
   assert(DelayedDiagnostics.getCurrentPool() == nullptr
          && "reached end of translation unit with a pool attached?");
 
-  if(SummarizerPtr)
-    SummarizerPtr->ActOnEndOfSourceFile();
+  if (SummaryCnsmr)
+    SummaryCnsmr->ProcessEndOfSourceFile();
+
   // If code completion is enabled, don't perform any end-of-translation-unit
   // work.
   if (PP.isCodeCompletionEnabled())
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 45f1523868f75..1aa7a1cf178bd 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -55,9 +55,9 @@
 #include "clang/Sema/SemaPPC.h"
 #include "clang/Sema/SemaRISCV.h"
 #include "clang/Sema/SemaSYCL.h"
-#include "clang/Sema/SemaSummarizer.h"
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaWasm.h"
+#include "clang/Sema/SummaryContext.h"
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -16695,8 +16695,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
   if (FD && !FD->isDeleted())
     checkTypeSupport(FD->getType(), FD->getLocation(), FD);
 
-  if (FD && SummarizerPtr && SummarizerPtr->TheSummaryConsumer)
-    SummarizerPtr->SummarizeFunctionBody(FD);
+  if (SummaryCnsmr) {
+    SummaryCtx->SummarizeFunctionBody(FD);
+    SummaryCnsmr->ProcessFunctionSummary(*SummaryCtx->GetSummary(FD));
+  }
 
   return dcl;
 }
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Sema/SummaryAttribute.cpp
index 6f141dde68e52..86d422c16fa30 100644
--- a/clang/lib/Sema/SummaryAttribute.cpp
+++ b/clang/lib/Sema/SummaryAttribute.cpp
@@ -1,5 +1,5 @@
 #include "clang/Sema/SummaryAttribute.h"
-#include "clang/Sema/SemaSummarizer.h"
+#include "clang/Sema/SummaryContext.h"
 
 namespace clang {
 void NoWriteGlobalAttr::Callback::run(
diff --git a/clang/lib/Sema/SummaryConsumer.cpp b/clang/lib/Sema/SummaryConsumer.cpp
index b10bc827f94ab..043873f236b93 100644
--- a/clang/lib/Sema/SummaryConsumer.cpp
+++ b/clang/lib/Sema/SummaryConsumer.cpp
@@ -1,5 +1,5 @@
 #include "clang/Sema/SummaryConsumer.h"
-#include "clang/Sema/SemaSummarizer.h"
+#include "clang/Sema/SummaryContext.h"
 
 namespace clang {
 void JSONPrintingSummaryConsumer::ProcessFunctionSummary(const FunctionSummary &Summary) {
diff --git a/clang/lib/Sema/SemaSummarizer.cpp b/clang/lib/Sema/SummaryContext.cpp
similarity index 82%
rename from clang/lib/Sema/SemaSummarizer.cpp
rename to clang/lib/Sema/SummaryContext.cpp
index 3b056fc53f8c9..6b7207eedb5e5 100644
--- a/clang/lib/Sema/SemaSummarizer.cpp
+++ b/clang/lib/Sema/SummaryContext.cpp
@@ -1,4 +1,4 @@
-#include "clang/Sema/SemaSummarizer.h"
+#include "clang/Sema/SummaryContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Index/USRGeneration.h"
 #include "clang/Sema/SummaryAttribute.h"
@@ -46,7 +46,7 @@ FunctionSummary::FunctionSummary(
     : ID(std::move(ID)), Attrs(std::move(FunctionAttrs)),
       Calls(std::move(Calls)) {}
 
-SummaryManager::SummaryManager() {
+SummaryContext::SummaryContext() {
   Attributes.emplace_back(std::make_unique<NoWriteGlobalAttr>());
 
   for (auto &&Attr : Attributes) {
@@ -56,7 +56,7 @@ SummaryManager::SummaryManager() {
   }
 }
 
-void SummaryManager::CreateSummary(SmallVector<char> ID,
+void SummaryContext::CreateSummary(SmallVector<char> ID,
                                    std::set<const SummaryAttribute *> Attrs,
                                    std::set<SmallVector<char>> Calls) {
   auto Summary = std::make_unique<FunctionSummary>(
@@ -66,12 +66,12 @@ void SummaryManager::CreateSummary(SmallVector<char> ID,
 }
 
 const FunctionSummary *
-SummaryManager::GetSummary(const FunctionDecl *FD) const {
+SummaryContext::GetSummary(const FunctionDecl *FD) const {
   auto USR = GetUSR(FD);
   return IDToSummary.count(USR) ? IDToSummary.at(USR) : nullptr;
 }
 
-void SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
+void SummaryContext::SummarizeFunctionBody(const FunctionDecl *FD) {
   std::set<const SummaryAttribute *> Attrs;
 
   for (auto &&Attr : Attributes) {
@@ -82,7 +82,7 @@ void SummaryManager::SummarizeFunctionBody(const FunctionDecl *FD) {
   CreateSummary(GetUSR(FD), std::move(Attrs), CallCollector().collect(FD));
 }
 
-void SummaryManager::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
+void SummaryContext::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
   for (auto it = Summary.begin(); it != Summary.end(); ++it) {
     const llvm::json::Object *FunctionSummary = it->getAsObject();
 
@@ -108,7 +108,7 @@ void SummaryManager::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
   }
 }
 
-bool SummaryManager::ReduceFunctionSummary(FunctionSummary &Function) {
+bool SummaryContext::ReduceFunctionSummary(FunctionSummary &Function) {
   bool changed = false;
 
   for (auto &&call : Function.getCalls()) {
@@ -137,7 +137,7 @@ bool SummaryManager::ReduceFunctionSummary(FunctionSummary &Function) {
   return changed;
 }
 
-void SummaryManager::ReduceSummaries() {
+void SummaryContext::ReduceSummaries() {
   bool changed = true;
   while (changed) {
     changed = false;
@@ -146,23 +146,4 @@ void SummaryManager::ReduceSummaries() {
       changed |= ReduceFunctionSummary(*Function);
   }
 }
-
-void SemaSummarizer::ActOnStartOfSourceFile() {
-  if(TheSummaryConsumer)
-    TheSummaryConsumer->ProcessStartOfSourceFile();
-}
-
-void SemaSummarizer::ActOnEndOfSourceFile() {
-  if(TheSummaryConsumer)
-    TheSummaryConsumer->ProcessEndOfSourceFile();
-}
-
-void SemaSummarizer::SummarizeFunctionBody(const FunctionDecl *FD) {
-  TheSummaryManager->SummarizeFunctionBody(FD);
-
-  if(TheSummaryConsumer)
-    TheSummaryConsumer->ProcessFunctionSummary(
-        *TheSummaryManager->GetSummary(FD));
-}
-
 } // namespace clang

>From d635e3221b8218337b0f80d54eae390d417bba5d Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 00:17:47 +0200
Subject: [PATCH 16/28] [clang][Summary] give the summary consumer a default
 value to keep the diff smaller

---
 clang/include/clang/Frontend/CompilerInstance.h | 2 +-
 clang/lib/Frontend/ChainedIncludesSource.cpp    | 2 +-
 clang/lib/Frontend/FrontendActions.cpp          | 2 +-
 clang/lib/Testing/TestAST.cpp                   | 2 +-
 clang/unittests/CodeGen/TestCompiler.h          | 2 +-
 clang/unittests/Frontend/CodeGenActionTest.cpp  | 2 +-
 clang/unittests/Sema/ExternalSemaSourceTest.cpp | 2 +-
 clang/unittests/Sema/SemaLookupTest.cpp         | 2 +-
 8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index b107f15af9563..7cb82e587cdfe 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -774,7 +774,7 @@ class CompilerInstance : public ModuleLoader {
   /// Create the Sema object to be used for parsing.
   void createSema(TranslationUnitKind TUKind,
                   CodeCompleteConsumer *CompletionConsumer,
-                  SummaryConsumer *SummaryConsumer);
+                  SummaryConsumer *SummaryConsumer = nullptr);
 
   /// Create the frontend timer and replace any existing one with it.
   void createFrontendTimer();
diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp
index 437f5387375f7..95b0ed248d545 100644
--- a/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -142,7 +142,7 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
     Clang->getASTContext().setASTMutationListener(
                                             consumer->GetASTMutationListener());
     Clang->setASTConsumer(std::move(consumer));
-    Clang->createSema(TU_Prefix, nullptr, nullptr);
+    Clang->createSema(TU_Prefix, nullptr);
 
     if (firstInclude) {
       Preprocessor &PP = Clang->getPreprocessor();
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 49f1420c75047..8c75e1a46da54 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -52,7 +52,7 @@ void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) {
 
   if (!CI.hasSema())
     CI.createSema(Action.getTranslationUnitKind(),
-                  GetCodeCompletionConsumer(CI), nullptr);
+                  GetCodeCompletionConsumer(CI));
 }
 } // namespace
 
diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp
index db0490689da53..748f59b856e83 100644
--- a/clang/lib/Testing/TestAST.cpp
+++ b/clang/lib/Testing/TestAST.cpp
@@ -69,7 +69,7 @@ void createMissingComponents(CompilerInstance &Clang) {
   if (!Clang.hasASTContext())
     Clang.createASTContext();
   if (!Clang.hasSema())
-    Clang.createSema(TU_Complete, /*CodeCompleteConsumer=*/nullptr, nullptr);
+    Clang.createSema(TU_Complete, /*CodeCompleteConsumer=*/nullptr);
 }
 
 } // namespace
diff --git a/clang/unittests/CodeGen/TestCompiler.h b/clang/unittests/CodeGen/TestCompiler.h
index 760fa340c3d74..a6fec7fb0945d 100644
--- a/clang/unittests/CodeGen/TestCompiler.h
+++ b/clang/unittests/CodeGen/TestCompiler.h
@@ -69,7 +69,7 @@ struct TestCompiler {
 
     compiler.setASTConsumer(std::move(Consumer));
 
-    compiler.createSema(clang::TU_Prefix, nullptr, nullptr);
+    compiler.createSema(clang::TU_Prefix, nullptr);
 
     clang::SourceManager &sm = compiler.getSourceManager();
     sm.setMainFileID(sm.createFileID(
diff --git a/clang/unittests/Frontend/CodeGenActionTest.cpp b/clang/unittests/Frontend/CodeGenActionTest.cpp
index e958ea1993a4a..90818b72cd6e6 100644
--- a/clang/unittests/Frontend/CodeGenActionTest.cpp
+++ b/clang/unittests/Frontend/CodeGenActionTest.cpp
@@ -37,7 +37,7 @@ class NullCodeGenAction : public CodeGenAction {
     if (!CI.hasPreprocessor())
       return;
     if (!CI.hasSema())
-      CI.createSema(getTranslationUnitKind(), nullptr, nullptr);
+      CI.createSema(getTranslationUnitKind(), nullptr);
   }
 };
 
diff --git a/clang/unittests/Sema/ExternalSemaSourceTest.cpp b/clang/unittests/Sema/ExternalSemaSourceTest.cpp
index d223a7135ee84..2b271d4bf7825 100644
--- a/clang/unittests/Sema/ExternalSemaSourceTest.cpp
+++ b/clang/unittests/Sema/ExternalSemaSourceTest.cpp
@@ -194,7 +194,7 @@ class ExternalSemaSourceInstaller : public clang::ASTFrontendAction {
   void ExecuteAction() override {
     CompilerInstance &CI = getCompilerInstance();
     ASSERT_FALSE(CI.hasSema());
-    CI.createSema(getTranslationUnitKind(), nullptr, nullptr);
+    CI.createSema(getTranslationUnitKind(), nullptr);
     ASSERT_TRUE(CI.hasDiagnostics());
     DiagnosticsEngine &Diagnostics = CI.getDiagnostics();
     DiagnosticConsumer *Client = Diagnostics.getClient();
diff --git a/clang/unittests/Sema/SemaLookupTest.cpp b/clang/unittests/Sema/SemaLookupTest.cpp
index 96c27945421f9..d97b571f6a37c 100644
--- a/clang/unittests/Sema/SemaLookupTest.cpp
+++ b/clang/unittests/Sema/SemaLookupTest.cpp
@@ -22,7 +22,7 @@ class LookupAction : public ASTFrontendAction {
   void ExecuteAction() override {
     CompilerInstance &CI = getCompilerInstance();
     ASSERT_FALSE(CI.hasSema());
-    CI.createSema(getTranslationUnitKind(), nullptr, nullptr);
+    CI.createSema(getTranslationUnitKind(), nullptr);
     ASSERT_TRUE(CI.hasSema());
     Sema &S = CI.getSema();
     ParseAST(S);

>From 757c0d6d3250203cdb70dc559303f4d8007c4ed5 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 02:01:47 +0200
Subject: [PATCH 17/28] [clang][Summary] change frontend action and summary
 interaction

---
 clang/lib/Frontend/FrontendAction.cpp | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 2821327c6a824..8e66d6b8a6c27 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -895,10 +895,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     }
   }
 
-  if (!CI.hasSummaryContext()) {
-    CI.createSummaryContext();
-  }
-
   // Set up embedding for any specified files. Do this before we load any
   // source files, including the primary module map for the compilation.
   for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
@@ -969,7 +965,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     }
   }
 
-  // FIXME: lookup dirs recursively
+  bool ProcessesSummaries = !CI.getFrontendOpts().SummaryDirPath.empty() ||
+                            !CI.getFrontendOpts().SummaryFile.empty();
+  if (ProcessesSummaries && !CI.hasSummaryContext())
+    CI.createSummaryContext();
+
+  // FIXME: cleanup and lookup dirs recursively
   if (!CI.getFrontendOpts().SummaryDirPath.empty()) {
     FileManager &FileMgr = CI.getFileManager();
 
@@ -1371,12 +1372,10 @@ void ASTFrontendAction::ExecuteAction() {
   if (CI.hasCodeCompletionConsumer())
     CompletionConsumer = &CI.getCodeCompletionConsumer();
 
-  if (!CI.hasSummaryContext()) {
-    CI.createSummaryContext();
-  }
-  CI.createSummaryConsumer();
+  if (!CI.getFrontendOpts().SummaryFile.empty())
+    CI.createSummaryConsumer();
 
-  // Use a code completion consumer?
+  // Use a code summary consumer?
   SummaryConsumer *SummaryConsumer = nullptr;
   if (CI.hasSummaryConsumer())
     SummaryConsumer = &CI.getSummaryConsumer();

>From f511c22187178d637b184d15fb2effaf1c08dd19 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 02:21:29 +0200
Subject: [PATCH 18/28] [clang][Summary] explicitly flush summary

---
 clang/include/clang/Sema/SummaryConsumer.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Sema/SummaryConsumer.h b/clang/include/clang/Sema/SummaryConsumer.h
index f8844ffb64e21..3d308b8464ef8 100644
--- a/clang/include/clang/Sema/SummaryConsumer.h
+++ b/clang/include/clang/Sema/SummaryConsumer.h
@@ -35,7 +35,10 @@ class JSONPrintingSummaryConsumer : public PrintingSummaryConsumer {
 
   void ProcessStartOfSourceFile() override { JOS.arrayBegin(); };
   void ProcessFunctionSummary(const FunctionSummary &) override;
-  void ProcessEndOfSourceFile() override { JOS.arrayEnd(); };
+  void ProcessEndOfSourceFile() override {
+    JOS.arrayEnd();
+    JOS.flush();
+  };
 };
 } // namespace clang
 

>From 6964f2c54db47c9ab748af19a55f4af761ed786b Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 03:00:33 +0200
Subject: [PATCH 19/28] [clang][analyzer][Summary] pass summaries to the
 analyzer

---
 .../StaticAnalyzer/Core/PathSensitive/ExprEngine.h    | 11 +++++++----
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp          |  5 +++--
 .../lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp  |  7 ++++++-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index b8a4dcbc727a6..5e3b338be6e68 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -21,18 +21,19 @@
 #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
 #include "clang/Analysis/ProgramPoint.h"
 #include "clang/Basic/LLVM.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/Sema/SummaryContext.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
 #include "llvm/ADT/ArrayRef.h"
 #include <cassert>
@@ -178,10 +179,12 @@ class ExprEngine {
   /// The flag, which specifies the mode of inlining for the engine.
   InliningModes HowToInline;
 
+  const SummaryContext *SummaryCtx;
+
 public:
   ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
-             SetOfConstDecls *VisitedCalleesIn,
-             FunctionSummariesTy *FS, InliningModes HowToInlineIn);
+             SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS,
+             InliningModes HowToInlineIn, const SummaryContext *SummaryCtx);
 
   virtual ~ExprEngine() = default;
 
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 1afd4b52eb354..c4836fb9d0aac 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -223,7 +223,8 @@ static const char* TagProviderName = "ExprEngine";
 
 ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
                        AnalysisManager &mgr, SetOfConstDecls *VisitedCalleesIn,
-                       FunctionSummariesTy *FS, InliningModes HowToInlineIn)
+                       FunctionSummariesTy *FS, InliningModes HowToInlineIn,
+                       const SummaryContext *SummaryCtx)
     : CTU(CTU), IsCTUEnabled(mgr.getAnalyzerOptions().IsNaiveCTUEnabled),
       AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
       Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()),
@@ -232,7 +233,7 @@ ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
       SymMgr(StateMgr.getSymbolManager()), MRMgr(StateMgr.getRegionManager()),
       svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()),
       BR(mgr, *this), VisitedCallees(VisitedCalleesIn),
-      HowToInline(HowToInlineIn) {
+      HowToInline(HowToInlineIn), SummaryCtx(SummaryCtx) {
   unsigned TrimInterval = mgr.options.GraphTrimInterval;
   if (TrimInterval != 0) {
     // Enable eager node reclamation when constructing the ExplodedGraph.
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 491aa93c96e49..b87014e4dcd00 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -93,6 +93,7 @@ class AnalysisConsumer : public AnalysisASTConsumer,
   ArrayRef<std::string> Plugins;
   std::unique_ptr<CodeInjector> Injector;
   cross_tu::CrossTranslationUnitContext CTU;
+  const SummaryContext *SummaryCtx;
 
   /// Stores the declarations from the local translation unit.
   /// Note, we pre-compute the local declarations at parse time as an
@@ -152,6 +153,9 @@ class AnalysisConsumer : public AnalysisASTConsumer,
     if (Opts.ShouldDisplayMacroExpansions)
       MacroExpansions.registerForPreprocessor(PP);
 
+    if (CI.hasSummaryContext())
+      SummaryCtx = &CI.getSummaryContext();
+
     // Visitor options.
     ShouldWalkTypesOfTypeLocs = false;
   }
@@ -761,7 +765,8 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
   if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
     return;
 
-  ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
+  ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode,
+                 SummaryCtx);
 
   // Execute the worklist algorithm.
   llvm::TimeRecord ExprEngineStartTime;

>From 81b039f8abc76f83583a809bc9e363122062305f Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 03:47:15 +0200
Subject: [PATCH 20/28] [analyzer] don't invalidate global regions if a
 function doesn't write them

---
 clang/include/clang/Sema/SummaryContext.h     |  1 +
 .../Core/PathSensitive/ExprEngine.h           |  2 ++
 clang/lib/Sema/SummaryContext.cpp             |  5 +++++
 clang/lib/StaticAnalyzer/Core/CallEvent.cpp   | 19 +++++++++++++++----
 4 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Sema/SummaryContext.h b/clang/include/clang/Sema/SummaryContext.h
index 67b1162d61763..2675a85583d69 100644
--- a/clang/include/clang/Sema/SummaryContext.h
+++ b/clang/include/clang/Sema/SummaryContext.h
@@ -42,6 +42,7 @@ class SummaryContext {
 public:
   SummaryContext();
 
+  const SummaryAttribute *GetAttribute(SummaryAttributeKind kind) const;
   const FunctionSummary *GetSummary(const FunctionDecl *FD) const;
   void SummarizeFunctionBody(const FunctionDecl *FD);
 
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 5e3b338be6e68..68a8004a8ae26 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -217,6 +217,8 @@ class ExprEngine {
     return &CTU;
   }
 
+  const SummaryContext *getSummaryCtx() { return SummaryCtx; }
+
   const NodeBuilderContext &getBuilderContext() {
     assert(currBldrCtx);
     return *currBldrCtx;
diff --git a/clang/lib/Sema/SummaryContext.cpp b/clang/lib/Sema/SummaryContext.cpp
index 6b7207eedb5e5..50771d2da0963 100644
--- a/clang/lib/Sema/SummaryContext.cpp
+++ b/clang/lib/Sema/SummaryContext.cpp
@@ -65,6 +65,11 @@ void SummaryContext::CreateSummary(SmallVector<char> ID,
   IDToSummary[SummaryPtr->getID()] = SummaryPtr;
 }
 
+const SummaryAttribute *
+SummaryContext::GetAttribute(SummaryAttributeKind kind) const {
+  return KindToAttribute.at(kind);
+}
+
 const FunctionSummary *
 SummaryContext::GetSummary(const FunctionDecl *FD) const {
   auto USR = GetUSR(FD);
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 583315f4f3a90..aa9a236ead9a3 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -277,13 +277,24 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
             ValuesToInvalidate.push_back(loc::MemRegionVal(TVR));
   }
 
+  bool ShouldPreserveGlobals = false;
+  const SummaryContext *SummaryCtx =
+      State->getStateManager().getOwningEngine().getSummaryCtx();
+  if (SummaryCtx) {
+    const auto *Summary =
+        SummaryCtx->GetSummary(llvm::dyn_cast<FunctionDecl>(getDecl()));
+    ShouldPreserveGlobals =
+        Summary && Summary->getAttributes().count(
+                       SummaryCtx->GetAttribute(NO_WRITE_GLOBAL));
+  }
+
   // Invalidate designated regions using the batch invalidation API.
   // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
   //  global variables.
-  return Result->invalidateRegions(ValuesToInvalidate, getCFGElementRef(),
-                                   BlockCount, getLocationContext(),
-                                   /*CausedByPointerEscape*/ true,
-                                   /*Symbols=*/nullptr, this, &ETraits);
+  return Result->invalidateRegions(
+      ValuesToInvalidate, getCFGElementRef(), BlockCount, getLocationContext(),
+      /*CausedByPointerEscape*/ true,
+      /*Symbols=*/nullptr, ShouldPreserveGlobals ? nullptr : this, &ETraits);
 }
 
 ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,

>From 016dcdb4707a0b8369ca0ef6a0fe788d1fb2f78f Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 14:50:08 +0200
Subject: [PATCH 21/28] [clang][Summary] refactor summary attributes

---
 clang/include/clang/Sema/SummaryAttribute.h | 36 +++++++++++++--------
 clang/include/clang/Sema/SummaryContext.h   | 30 ++++++++++-------
 clang/lib/Sema/SummaryContext.cpp           | 35 +++++++++-----------
 clang/lib/StaticAnalyzer/Core/CallEvent.cpp |  9 +++---
 4 files changed, 60 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index 0014a9878bacd..b3b8d452dfd18 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -3,37 +3,40 @@
 
 #include "clang/AST/Decl.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
-#include <string>
 
 namespace clang {
-enum SummaryAttributeKind {
+enum SummaryAttrKind {
   NO_WRITE_GLOBAL,
 };
 
 class FunctionSummary;
+class SummaryContext;
 
-class SummaryAttribute {
-  const SummaryAttributeKind Kind;
-  std::string_view Serialzed;
+class SummaryAttr {
+  const SummaryAttrKind Kind;
+  const char *Spelling;
+
+protected:
+  SummaryAttr(SummaryAttrKind Kind, const char *Spelling)
+      : Kind(Kind), Spelling(Spelling){};
 
 public:
-  SummaryAttribute(SummaryAttributeKind Attr, const char *Str)
-      : Kind(Attr), Serialzed(Str) {}
-  virtual ~SummaryAttribute() = default;
+  virtual ~SummaryAttr() = default;
 
-  SummaryAttributeKind getKind() { return Kind; }
+  SummaryAttrKind getKind() const { return Kind; }
+  const char *getSpelling() const { return Spelling; }
 
   virtual bool infer(const FunctionDecl *FD) const = 0;
   virtual bool merge(const FunctionSummary &Caller,
                      const FunctionSummary &Callee) const = 0;
 
-  virtual std::string serialize() const { return std::string(Serialzed); };
+  virtual std::string serialize() const { return std::string(Spelling); };
   virtual bool parse(std::string_view input) const {
-    return input == Serialzed;
+    return input == Spelling;
   };
 };
 
-class NoWriteGlobalAttr : public SummaryAttribute {
+class NoWriteGlobalAttr : public SummaryAttr {
   class Callback : public ast_matchers::MatchFinder::MatchCallback {
   public:
     bool WriteGlobal = false;
@@ -42,12 +45,17 @@ class NoWriteGlobalAttr : public SummaryAttribute {
     run(const ast_matchers::MatchFinder::MatchResult &Result) override final;
   };
 
-public:
-  NoWriteGlobalAttr() : SummaryAttribute(NO_WRITE_GLOBAL, "no_write_global") {}
+  NoWriteGlobalAttr() : SummaryAttr(NO_WRITE_GLOBAL, "no_write_global") {}
 
+public:
   bool infer(const FunctionDecl *FD) const override final;
   bool merge(const FunctionSummary &Caller,
              const FunctionSummary &Callee) const override final;
+
+  static bool classof(const SummaryAttr *A) {
+    return A->getKind() == NO_WRITE_GLOBAL;
+  }
+  friend class SummaryContext;
 };
 } // namespace clang
 
diff --git a/clang/include/clang/Sema/SummaryContext.h b/clang/include/clang/Sema/SummaryContext.h
index 2675a85583d69..c142484b131dc 100644
--- a/clang/include/clang/Sema/SummaryContext.h
+++ b/clang/include/clang/Sema/SummaryContext.h
@@ -8,21 +8,27 @@
 namespace clang {
 class FunctionSummary {
   SmallVector<char> ID;
-  std::set<const SummaryAttribute *> Attrs;
+  std::set<const SummaryAttr *> Attrs;
   std::set<SmallVector<char>> Calls;
 
 public:
-  FunctionSummary(SmallVector<char> ID,
-                  std::set<const SummaryAttribute *> Attrs,
+  FunctionSummary(SmallVector<char> ID, std::set<const SummaryAttr *> Attrs,
                   std::set<SmallVector<char>> Calls);
 
   SmallVector<char> getID() const { return ID; }
-  const std::set<const SummaryAttribute *> &getAttributes() const {
-    return Attrs;
-  }
+  const std::set<const SummaryAttr *> &getAttributes() const { return Attrs; }
   const std::set<SmallVector<char>> &getCalls() const { return Calls; }
 
-  void replaceAttributes(std::set<const SummaryAttribute *> Attrs) {
+  template <typename T> bool hasAttribute() const {
+    for (auto &&attr : Attrs) {
+      if (llvm::isa<T>(attr))
+        return true;
+    }
+
+    return false;
+  }
+
+  void replaceAttributes(std::set<const SummaryAttr *> Attrs) {
     this->Attrs = std::move(Attrs);
   }
 };
@@ -31,18 +37,18 @@ class SummaryContext {
   std::map<SmallVector<char>, const FunctionSummary *> IDToSummary;
   std::vector<std::unique_ptr<FunctionSummary>> FunctionSummaries;
 
-  std::map<SummaryAttributeKind, const SummaryAttribute *> KindToAttribute;
-  std::vector<std::unique_ptr<SummaryAttribute>> Attributes;
+  std::map<SummaryAttrKind, const SummaryAttr *> KindToAttribute;
+  std::vector<std::unique_ptr<SummaryAttr>> Attributes;
 
-  void CreateSummary(SmallVector<char> ID,
-                     std::set<const SummaryAttribute *> Attrs,
+  void CreateSummary(SmallVector<char> ID, std::set<const SummaryAttr *> Attrs,
                      std::set<SmallVector<char>> Calls);
   bool ReduceFunctionSummary(FunctionSummary &FunctionSummary);
 
+  template <typename T> void registerAttr();
+
 public:
   SummaryContext();
 
-  const SummaryAttribute *GetAttribute(SummaryAttributeKind kind) const;
   const FunctionSummary *GetSummary(const FunctionDecl *FD) const;
   void SummarizeFunctionBody(const FunctionDecl *FD);
 
diff --git a/clang/lib/Sema/SummaryContext.cpp b/clang/lib/Sema/SummaryContext.cpp
index 50771d2da0963..b4e49451030c0 100644
--- a/clang/lib/Sema/SummaryContext.cpp
+++ b/clang/lib/Sema/SummaryContext.cpp
@@ -40,24 +40,26 @@ class CallCollector : public ast_matchers::MatchFinder::MatchCallback {
 };
 } // namespace
 
-FunctionSummary::FunctionSummary(
-    SmallVector<char> ID, std::set<const SummaryAttribute *> FunctionAttrs,
-    std::set<SmallVector<char>> Calls)
+FunctionSummary::FunctionSummary(SmallVector<char> ID,
+                                 std::set<const SummaryAttr *> FunctionAttrs,
+                                 std::set<SmallVector<char>> Calls)
     : ID(std::move(ID)), Attrs(std::move(FunctionAttrs)),
       Calls(std::move(Calls)) {}
 
-SummaryContext::SummaryContext() {
-  Attributes.emplace_back(std::make_unique<NoWriteGlobalAttr>());
+template <typename T> void SummaryContext::registerAttr() {
+  std::unique_ptr<T> attr(new T());
+  SummaryAttrKind Kind = attr->getKind();
 
-  for (auto &&Attr : Attributes) {
-    assert(KindToAttribute.count(Attr->getKind()) == 0 &&
-           "Attr already registered");
-    KindToAttribute[Attr->getKind()] = Attr.get();
-  }
+  if (KindToAttribute.count(Kind))
+    return;
+
+  KindToAttribute[Kind] = Attributes.emplace_back(std::move(attr)).get();
 }
 
+SummaryContext::SummaryContext() { registerAttr<NoWriteGlobalAttr>(); }
+
 void SummaryContext::CreateSummary(SmallVector<char> ID,
-                                   std::set<const SummaryAttribute *> Attrs,
+                                   std::set<const SummaryAttr *> Attrs,
                                    std::set<SmallVector<char>> Calls) {
   auto Summary = std::make_unique<FunctionSummary>(
       std::move(ID), std::move(Attrs), std::move(Calls));
@@ -65,11 +67,6 @@ void SummaryContext::CreateSummary(SmallVector<char> ID,
   IDToSummary[SummaryPtr->getID()] = SummaryPtr;
 }
 
-const SummaryAttribute *
-SummaryContext::GetAttribute(SummaryAttributeKind kind) const {
-  return KindToAttribute.at(kind);
-}
-
 const FunctionSummary *
 SummaryContext::GetSummary(const FunctionDecl *FD) const {
   auto USR = GetUSR(FD);
@@ -77,7 +74,7 @@ SummaryContext::GetSummary(const FunctionDecl *FD) const {
 }
 
 void SummaryContext::SummarizeFunctionBody(const FunctionDecl *FD) {
-  std::set<const SummaryAttribute *> Attrs;
+  std::set<const SummaryAttr *> Attrs;
 
   for (auto &&Attr : Attributes) {
     if (Attr->infer(FD))
@@ -92,7 +89,7 @@ void SummaryContext::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
     const llvm::json::Object *FunctionSummary = it->getAsObject();
 
     SmallString<128> ID(*FunctionSummary->getString("id"));
-    std::set<const SummaryAttribute *> FunctionAttrs;
+    std::set<const SummaryAttr *> FunctionAttrs;
     const llvm::json::Array *FunctionAttributes =
         FunctionSummary->getObject("attrs")->getArray("function");
     for(auto attrIt = FunctionAttributes->begin(); attrIt != FunctionAttributes->end(); ++attrIt) {
@@ -117,7 +114,7 @@ bool SummaryContext::ReduceFunctionSummary(FunctionSummary &Function) {
   bool changed = false;
 
   for (auto &&call : Function.getCalls()) {
-    std::set<const SummaryAttribute *> reducedAttrs;
+    std::set<const SummaryAttr *> reducedAttrs;
 
     // If we don't have a summary about a called function, we forget
     // everything about the current one as well.
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index aa9a236ead9a3..a4885f62be627 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -280,12 +280,11 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
   bool ShouldPreserveGlobals = false;
   const SummaryContext *SummaryCtx =
       State->getStateManager().getOwningEngine().getSummaryCtx();
-  if (SummaryCtx) {
-    const auto *Summary =
-        SummaryCtx->GetSummary(llvm::dyn_cast<FunctionDecl>(getDecl()));
+  const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(getDecl());
+  if (SummaryCtx && FD) {
+    const auto *Summary = SummaryCtx->GetSummary(FD);
     ShouldPreserveGlobals =
-        Summary && Summary->getAttributes().count(
-                       SummaryCtx->GetAttribute(NO_WRITE_GLOBAL));
+        Summary && Summary->hasAttribute<NoWriteGlobalAttr>();
   }
 
   // Invalidate designated regions using the batch invalidation API.

>From 115584471eb25cd5211d8bda0854c17b2bf3eee4 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 14:57:16 +0200
Subject: [PATCH 22/28] [Summary] move the ast matcher callback out of the
 attribute declaration

---
 clang/include/clang/Sema/SummaryAttribute.h |  8 -------
 clang/lib/Sema/SummaryAttribute.cpp         | 25 ++++++++++++---------
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Sema/SummaryAttribute.h
index b3b8d452dfd18..27ceede1e4486 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Sema/SummaryAttribute.h
@@ -37,14 +37,6 @@ class SummaryAttr {
 };
 
 class NoWriteGlobalAttr : public SummaryAttr {
-  class Callback : public ast_matchers::MatchFinder::MatchCallback {
-  public:
-    bool WriteGlobal = false;
-
-    void
-    run(const ast_matchers::MatchFinder::MatchResult &Result) override final;
-  };
-
   NoWriteGlobalAttr() : SummaryAttr(NO_WRITE_GLOBAL, "no_write_global") {}
 
 public:
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Sema/SummaryAttribute.cpp
index 86d422c16fa30..6bb6b938184de 100644
--- a/clang/lib/Sema/SummaryAttribute.cpp
+++ b/clang/lib/Sema/SummaryAttribute.cpp
@@ -2,19 +2,24 @@
 #include "clang/Sema/SummaryContext.h"
 
 namespace clang {
-void NoWriteGlobalAttr::Callback::run(
-    const ast_matchers::MatchFinder::MatchResult &Result) {
-  const auto *Assignment = Result.Nodes.getNodeAs<BinaryOperator>("assignment");
-  if (!Assignment)
-    return;
-
-  WriteGlobal = true;
-}
-
 bool NoWriteGlobalAttr::infer(const FunctionDecl *FD) const {
   using namespace ast_matchers;
   MatchFinder Finder;
-  Callback CB;
+
+  class Callback : public ast_matchers::MatchFinder::MatchCallback {
+  public:
+    bool WriteGlobal = false;
+
+    void
+    run(const ast_matchers::MatchFinder::MatchResult &Result) override final {
+      const auto *Assignment =
+          Result.Nodes.getNodeAs<BinaryOperator>("assignment");
+      if (!Assignment)
+        return;
+
+      WriteGlobal = true;
+    }
+  } CB;
 
   Finder.addMatcher(
       functionDecl(forEachDescendant(

>From 49937a6570ff49042b72a286896647dcdd926cb9 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 15:07:56 +0200
Subject: [PATCH 23/28] [clang] don't crash if there is no summary consumer

---
 clang/lib/Frontend/CompilerInstance.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 448d45b0f49db..9682a01fab226 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -764,7 +764,8 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind,
                                   CodeCompleteConsumer *CompletionConsumer,
                                   SummaryConsumer *SummaryConsumer) {
   TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(),
-                         TUKind, CompletionConsumer, &getSummaryContext(),
+                         TUKind, CompletionConsumer,
+                         hasSummaryContext() ? &getSummaryContext() : nullptr,
                          SummaryConsumer));
 
   // Set up API notes.

>From 2499ff2e7f92537a5617f7c91a6dfb14e0c2e179 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 15:50:54 +0200
Subject: [PATCH 24/28] [Driver][Summary] implement emitting summary next to
 the object file

---
 clang/lib/Driver/ToolChains/Clang.cpp | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 48b19615ab08f..f61bb983900f4 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5473,7 +5473,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (Args.getLastArg(options::OPT_summaries_dir_EQ))
     Args.AddLastArg(CmdArgs, options::OPT_summaries_dir_EQ);
 
-  // FIXME: This needs to be cleaned up and needs proper error handling as well.
   if (const Arg *A = Args.getLastArg(options::OPT_emit_summaries_EQ)) {
     llvm::SmallString<10> input;
     for (const auto &II : Inputs) {
@@ -5485,14 +5484,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     }
 
     if (!input.empty()) {
-      if (A->containsValue("cwd")) {
-        llvm::SmallString<10> filename = llvm::sys::path::filename(input);
-        llvm::sys::path::replace_extension(filename, "json");
+      Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+      StringRef filename = llvm::sys::path::filename(input);
+      llvm::SmallString<10> summaryFile;
+
+      if (A->containsValue("cwd") || !FinalOutput) {
+        summaryFile = filename;
+      } else if (A->containsValue("obj") && FinalOutput) {
+        summaryFile = llvm::sys::path::parent_path(FinalOutput->getValue());
+        llvm::sys::path::append(summaryFile, filename);
+      }
 
+      if (!summaryFile.empty()) {
+        llvm::sys::path::replace_extension(summaryFile, "json");
         CmdArgs.push_back(
-            Args.MakeArgString(Twine("-summary-file=") + filename));
-      } else if (A->containsValue("obj")) {
-        // FIXME: implement
+            Args.MakeArgString(Twine("-summary-file=") + summaryFile));
       }
     }
   }

>From d44d9d051426b72ebf9f2b0de1e7b11ef2ae5635 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 16:23:29 +0200
Subject: [PATCH 25/28] [Summary] move summary related logic into a separate
 library

---
 clang/include/clang/Frontend/CompilerInstance.h    |  2 +-
 .../StaticAnalyzer/Core/PathSensitive/ExprEngine.h |  2 +-
 .../clang/{Sema => Summary}/SummaryAttribute.h     |  6 +++---
 .../clang/{Sema => Summary}/SummaryConsumer.h      |  8 ++++----
 .../clang/{Sema => Summary}/SummaryContext.h       | 10 +++++-----
 clang/lib/CMakeLists.txt                           |  1 +
 clang/lib/Frontend/CompilerInstance.cpp            |  2 +-
 clang/lib/Frontend/FrontendAction.cpp              |  2 +-
 clang/lib/Sema/CMakeLists.txt                      |  4 +---
 clang/lib/Sema/Sema.cpp                            |  2 +-
 clang/lib/Sema/SemaDecl.cpp                        |  2 +-
 clang/lib/Summary/CMakeLists.txt                   | 14 ++++++++++++++
 clang/lib/{Sema => Summary}/SummaryAttribute.cpp   |  4 ++--
 clang/lib/{Sema => Summary}/SummaryConsumer.cpp    |  7 ++++---
 clang/lib/{Sema => Summary}/SummaryContext.cpp     | 12 +++++++-----
 15 files changed, 47 insertions(+), 31 deletions(-)
 rename clang/include/clang/{Sema => Summary}/SummaryAttribute.h (90%)
 rename clang/include/clang/{Sema => Summary}/SummaryConsumer.h (87%)
 rename clang/include/clang/{Sema => Summary}/SummaryContext.h (87%)
 create mode 100644 clang/lib/Summary/CMakeLists.txt
 rename clang/lib/{Sema => Summary}/SummaryAttribute.cpp (92%)
 rename clang/lib/{Sema => Summary}/SummaryConsumer.cpp (74%)
 rename clang/lib/{Sema => Summary}/SummaryContext.cpp (92%)

diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index 7cb82e587cdfe..4a15fbf042cce 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -19,7 +19,7 @@
 #include "clang/Lex/DependencyDirectivesScanner.h"
 #include "clang/Lex/HeaderSearchOptions.h"
 #include "clang/Lex/ModuleLoader.h"
-#include "clang/Sema/SummaryContext.h"
+#include "clang/Summary/SummaryContext.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 68a8004a8ae26..e349dcbbfb9c4 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -21,7 +21,6 @@
 #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
 #include "clang/Analysis/ProgramPoint.h"
 #include "clang/Basic/LLVM.h"
-#include "clang/Sema/SummaryContext.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -35,6 +34,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
+#include "clang/Summary/SummaryContext.h"
 #include "llvm/ADT/ArrayRef.h"
 #include <cassert>
 #include <optional>
diff --git a/clang/include/clang/Sema/SummaryAttribute.h b/clang/include/clang/Summary/SummaryAttribute.h
similarity index 90%
rename from clang/include/clang/Sema/SummaryAttribute.h
rename to clang/include/clang/Summary/SummaryAttribute.h
index 27ceede1e4486..46de04a8169eb 100644
--- a/clang/include/clang/Sema/SummaryAttribute.h
+++ b/clang/include/clang/Summary/SummaryAttribute.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_CLANG_SEMA_SEMASUMMARYATTRIBUTE_H
-#define LLVM_CLANG_SEMA_SEMASUMMARYATTRIBUTE_H
+#ifndef LLVM_CLANG_SUMMARY_SUMMARYATTRIBUTE_H
+#define LLVM_CLANG_SUMMARY_SUMMARYATTRIBUTE_H
 
 #include "clang/AST/Decl.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -51,4 +51,4 @@ class NoWriteGlobalAttr : public SummaryAttr {
 };
 } // namespace clang
 
-#endif // LLVM_CLANG_SEMA_SEMASUMMARYATTRIBUTEH
+#endif // LLVM_CLANG_SUMMARY_SUMMARYATTRIBUTEH
diff --git a/clang/include/clang/Sema/SummaryConsumer.h b/clang/include/clang/Summary/SummaryConsumer.h
similarity index 87%
rename from clang/include/clang/Sema/SummaryConsumer.h
rename to clang/include/clang/Summary/SummaryConsumer.h
index 3d308b8464ef8..f0b14b3db7c79 100644
--- a/clang/include/clang/Sema/SummaryConsumer.h
+++ b/clang/include/clang/Summary/SummaryConsumer.h
@@ -1,5 +1,5 @@
-#ifndef LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
-#define LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
+#ifndef LLVM_CLANG_SUMMARY_SUMMARYCONSUMER_H
+#define LLVM_CLANG_SUMMARY_SUMMARYCONSUMER_H
 
 #include "clang/Basic/LLVM.h"
 #include "llvm/Support/JSON.h"
@@ -27,7 +27,7 @@ class PrintingSummaryConsumer : public SummaryConsumer {
 };
 
 class JSONPrintingSummaryConsumer : public PrintingSummaryConsumer {
-    llvm::json::OStream JOS;
+  llvm::json::OStream JOS;
 
 public:
   JSONPrintingSummaryConsumer(const SummaryContext &SummaryCtx, raw_ostream &OS)
@@ -42,4 +42,4 @@ class JSONPrintingSummaryConsumer : public PrintingSummaryConsumer {
 };
 } // namespace clang
 
-#endif // LLVM_CLANG_SEMA_SUMMARYCONSUMER_H
+#endif // LLVM_CLANG_SUMMARY_SUMMARYCONSUMER_H
diff --git a/clang/include/clang/Sema/SummaryContext.h b/clang/include/clang/Summary/SummaryContext.h
similarity index 87%
rename from clang/include/clang/Sema/SummaryContext.h
rename to clang/include/clang/Summary/SummaryContext.h
index c142484b131dc..194f89a4b4007 100644
--- a/clang/include/clang/Sema/SummaryContext.h
+++ b/clang/include/clang/Summary/SummaryContext.h
@@ -1,8 +1,8 @@
-#ifndef LLVM_CLANG_SEMA_SEMASUMMARYCONTEXT_H
-#define LLVM_CLANG_SEMA_SEMASUMMARYCONTEXT_H
+#ifndef LLVM_CLANG_SUMMARY_SUMMARYCONTEXT_H
+#define LLVM_CLANG_SUMMARY_SUMMARYCONTEXT_H
 
-#include "clang/Sema/SummaryAttribute.h"
-#include "clang/Sema/SummaryConsumer.h"
+#include "clang/Summary/SummaryAttribute.h"
+#include "clang/Summary/SummaryConsumer.h"
 #include <set>
 
 namespace clang {
@@ -57,4 +57,4 @@ class SummaryContext {
 };
 } // namespace clang
 
-#endif // LLVM_CLANG_SEMA_SEMASUMMARYCONTEXTH
+#endif // LLVM_CLANG_SUMMARY_SUMMARYCONTEXTH
diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt
index 4f2218b583e41..96f0ccd7d1c88 100644
--- a/clang/lib/CMakeLists.txt
+++ b/clang/lib/CMakeLists.txt
@@ -9,6 +9,7 @@ add_subdirectory(CrossTU)
 add_subdirectory(Sema)
 add_subdirectory(CodeGen)
 add_subdirectory(Analysis)
+add_subdirectory(Summary)
 add_subdirectory(Edit)
 add_subdirectory(ExtractAPI)
 add_subdirectory(Rewrite)
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 9682a01fab226..c75a4056e2847 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -37,11 +37,11 @@
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "clang/Sema/ParsedAttr.h"
 #include "clang/Sema/Sema.h"
-#include "clang/Sema/SummaryConsumer.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/GlobalModuleIndex.h"
 #include "clang/Serialization/InMemoryModuleCache.h"
 #include "clang/Serialization/ModuleCache.h"
+#include "clang/Summary/SummaryConsumer.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 8e66d6b8a6c27..966c514e04a96 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -35,10 +35,10 @@
 #include "clang/Parse/ParseAST.h"
 #include "clang/Sema/HLSLExternalSemaSource.h"
 #include "clang/Sema/MultiplexExternalSemaSource.h"
-#include "clang/Sema/SummaryContext.h"
 #include "clang/Serialization/ASTDeserializationListener.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Summary/SummaryContext.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/BuryPointer.h"
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 9d5a593813bd3..940456e15f9f8 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -98,9 +98,6 @@ add_clang_library(clangSema
   SemaType.cpp
   SemaWasm.cpp
   SemaX86.cpp
-  SummaryAttribute.cpp
-  SummaryConsumer.cpp
-  SummaryContext.cpp
   TypeLocBuilder.cpp
 
   DEPENDS
@@ -117,4 +114,5 @@ add_clang_library(clangSema
   clangEdit
   clangLex
   clangSupport
+  clangSummary
   )
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 2870871876701..5c5fb005a3172 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -68,10 +68,10 @@
 #include "clang/Sema/SemaSystemZ.h"
 #include "clang/Sema/SemaWasm.h"
 #include "clang/Sema/SemaX86.h"
-#include "clang/Sema/SummaryContext.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/Sema/TemplateInstCallback.h"
 #include "clang/Sema/TypoCorrection.h"
+#include "clang/Summary/SummaryContext.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1aa7a1cf178bd..740fccc3aad33 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -57,8 +57,8 @@
 #include "clang/Sema/SemaSYCL.h"
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaWasm.h"
-#include "clang/Sema/SummaryContext.h"
 #include "clang/Sema/Template.h"
+#include "clang/Summary/SummaryContext.h"
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
diff --git a/clang/lib/Summary/CMakeLists.txt b/clang/lib/Summary/CMakeLists.txt
new file mode 100644
index 0000000000000..269d09cb10d16
--- /dev/null
+++ b/clang/lib/Summary/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS
+  Core
+  Support
+  )
+
+add_clang_library(clangSummary
+  SummaryAttribute.cpp
+  SummaryConsumer.cpp
+  SummaryContext.cpp
+
+  LINK_LIBS
+  clangAST
+  clangSupport
+  )
diff --git a/clang/lib/Sema/SummaryAttribute.cpp b/clang/lib/Summary/SummaryAttribute.cpp
similarity index 92%
rename from clang/lib/Sema/SummaryAttribute.cpp
rename to clang/lib/Summary/SummaryAttribute.cpp
index 6bb6b938184de..c9a69140c5494 100644
--- a/clang/lib/Sema/SummaryAttribute.cpp
+++ b/clang/lib/Summary/SummaryAttribute.cpp
@@ -1,5 +1,5 @@
-#include "clang/Sema/SummaryAttribute.h"
-#include "clang/Sema/SummaryContext.h"
+#include "clang/Summary/SummaryAttribute.h"
+#include "clang/Summary/SummaryContext.h"
 
 namespace clang {
 bool NoWriteGlobalAttr::infer(const FunctionDecl *FD) const {
diff --git a/clang/lib/Sema/SummaryConsumer.cpp b/clang/lib/Summary/SummaryConsumer.cpp
similarity index 74%
rename from clang/lib/Sema/SummaryConsumer.cpp
rename to clang/lib/Summary/SummaryConsumer.cpp
index 043873f236b93..716248ffc9e24 100644
--- a/clang/lib/Sema/SummaryConsumer.cpp
+++ b/clang/lib/Summary/SummaryConsumer.cpp
@@ -1,8 +1,9 @@
-#include "clang/Sema/SummaryConsumer.h"
-#include "clang/Sema/SummaryContext.h"
+#include "clang/Summary/SummaryConsumer.h"
+#include "clang/Summary/SummaryContext.h"
 
 namespace clang {
-void JSONPrintingSummaryConsumer::ProcessFunctionSummary(const FunctionSummary &Summary) {
+void JSONPrintingSummaryConsumer::ProcessFunctionSummary(
+    const FunctionSummary &Summary) {
   JOS.object([&] {
     JOS.attribute("id", llvm::json::Value(Summary.getID()));
     JOS.attributeObject("attrs", [&] {
diff --git a/clang/lib/Sema/SummaryContext.cpp b/clang/lib/Summary/SummaryContext.cpp
similarity index 92%
rename from clang/lib/Sema/SummaryContext.cpp
rename to clang/lib/Summary/SummaryContext.cpp
index b4e49451030c0..6cb4b7a716200 100644
--- a/clang/lib/Sema/SummaryContext.cpp
+++ b/clang/lib/Summary/SummaryContext.cpp
@@ -1,8 +1,8 @@
-#include "clang/Sema/SummaryContext.h"
+#include "clang/Summary/SummaryContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Index/USRGeneration.h"
-#include "clang/Sema/SummaryAttribute.h"
-#include "clang/Sema/SummaryConsumer.h"
+#include "clang/Summary/SummaryAttribute.h"
+#include "clang/Summary/SummaryConsumer.h"
 #include <set>
 
 namespace clang {
@@ -92,7 +92,8 @@ void SummaryContext::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
     std::set<const SummaryAttr *> FunctionAttrs;
     const llvm::json::Array *FunctionAttributes =
         FunctionSummary->getObject("attrs")->getArray("function");
-    for(auto attrIt = FunctionAttributes->begin(); attrIt != FunctionAttributes->end(); ++attrIt) {
+    for (auto attrIt = FunctionAttributes->begin();
+         attrIt != FunctionAttributes->end(); ++attrIt) {
       for (auto &&Attr : Attributes) {
         if (Attr->parse(*attrIt->getAsString()))
           FunctionAttrs.emplace(Attr.get());
@@ -101,7 +102,8 @@ void SummaryContext::ParseSummaryFromJSON(const llvm::json::Array &Summary) {
 
     std::set<SmallVector<char>> Calls;
     const llvm::json::Array *CallEntries = FunctionSummary->getArray("calls");
-    for(auto callIt = CallEntries->begin(); callIt != CallEntries->end(); ++callIt) {
+    for (auto callIt = CallEntries->begin(); callIt != CallEntries->end();
+         ++callIt) {
       auto *Obj = callIt->getAsObject();
       Calls.emplace(SmallString<128>(*Obj->getString("id")));
     }

>From 9e94174cf526adf00825311b5cb8f69a1baff69b Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 21:01:39 +0200
Subject: [PATCH 26/28] link clangSummary against clangIndex

---
 clang/lib/Summary/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/Summary/CMakeLists.txt b/clang/lib/Summary/CMakeLists.txt
index 269d09cb10d16..a8d7d065d11c2 100644
--- a/clang/lib/Summary/CMakeLists.txt
+++ b/clang/lib/Summary/CMakeLists.txt
@@ -11,4 +11,5 @@ add_clang_library(clangSummary
   LINK_LIBS
   clangAST
   clangSupport
+  clangIndex
   )

>From 41c286bb417cd053d351d1710e3195dbac5f73a7 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 21:05:25 +0200
Subject: [PATCH 27/28] format

---
 clang/include/clang/Summary/SummaryAttribute.h | 2 +-
 clang/include/clang/Summary/SummaryConsumer.h  | 6 +++---
 clang/lib/Frontend/CompilerInstance.cpp        | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Summary/SummaryAttribute.h b/clang/include/clang/Summary/SummaryAttribute.h
index 46de04a8169eb..a736305b25f5b 100644
--- a/clang/include/clang/Summary/SummaryAttribute.h
+++ b/clang/include/clang/Summary/SummaryAttribute.h
@@ -18,7 +18,7 @@ class SummaryAttr {
 
 protected:
   SummaryAttr(SummaryAttrKind Kind, const char *Spelling)
-      : Kind(Kind), Spelling(Spelling){};
+      : Kind(Kind), Spelling(Spelling) {};
 
 public:
   virtual ~SummaryAttr() = default;
diff --git a/clang/include/clang/Summary/SummaryConsumer.h b/clang/include/clang/Summary/SummaryConsumer.h
index f0b14b3db7c79..a9f8abb78aff9 100644
--- a/clang/include/clang/Summary/SummaryConsumer.h
+++ b/clang/include/clang/Summary/SummaryConsumer.h
@@ -15,9 +15,9 @@ class SummaryConsumer {
   SummaryConsumer(const SummaryContext &SummaryCtx) : SummaryCtx(&SummaryCtx) {}
   virtual ~SummaryConsumer() = default;
 
-  virtual void ProcessStartOfSourceFile(){};
-  virtual void ProcessFunctionSummary(const FunctionSummary &){};
-  virtual void ProcessEndOfSourceFile(){};
+  virtual void ProcessStartOfSourceFile() {};
+  virtual void ProcessFunctionSummary(const FunctionSummary &) {};
+  virtual void ProcessEndOfSourceFile() {};
 };
 
 class PrintingSummaryConsumer : public SummaryConsumer {
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index c75a4056e2847..634e5234a5912 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -743,8 +743,8 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
 }
 
 void CompilerInstance::createSummaryConsumer() {
-  const std::string& SummaryFile = getFrontendOpts().SummaryFile;
-  if(SummaryFile.empty())
+  const std::string &SummaryFile = getFrontendOpts().SummaryFile;
+  if (SummaryFile.empty())
     return;
 
   std::error_code EC;

>From 103956b7d9caafe46b2fa45fad1173f4bb77e54a Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Sat, 14 Jun 2025 21:55:29 +0200
Subject: [PATCH 28/28] make the summary context in the expression engine
 nullptr by default

---
 .../clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h       | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index e349dcbbfb9c4..ac010e424da40 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -184,7 +184,8 @@ class ExprEngine {
 public:
   ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
              SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS,
-             InliningModes HowToInlineIn, const SummaryContext *SummaryCtx);
+             InliningModes HowToInlineIn,
+             const SummaryContext *SummaryCtx = nullptr);
 
   virtual ~ExprEngine() = default;
 



More information about the cfe-commits mailing list