[llvm-branch-commits] [clang-tools-extra] [include-cleaner] add fragment header analysis (PR #196764)

2026-06-06 Thread Daniil Dudkin via llvm-branch-commits

https://github.com/unterumarmung edited 
https://github.com/llvm/llvm-project/pull/196764
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang-tools-extra] [include-cleaner] add fragment header analysis (PR #196764)

2026-05-10 Thread via llvm-branch-commits

llvmorg-github-actions[bot] wrote:




@llvm/pr-subscribers-clang-tools-extra

Author: Daniil Dudkin (unterumarmung)


Changes



---

Patch is 30.10 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/196764.diff


4 Files Affected:

- (modified) 
clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h 
(+29) 
- (modified) clang-tools-extra/include-cleaner/lib/Analysis.cpp (+219-59) 
- (modified) clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp (+1-1) 
- (modified) clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp 
(+318-7) 


``diff
diff --git 
a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h 
b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
index 8e4912fa7bd84..1d28d87c025ca 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
@@ -62,24 +62,53 @@ void walkUsed(llvm::ArrayRef ASTRoots,
   const PragmaIncludes *PI, const Preprocessor &PP,
   UsedSymbolCB CB);
 
+/// A location kind where a symbol reference is observed.
+enum class SymbolReferenceOrigin {
+  MainFile,
+  Preamble,
+  Fragment,
+};
+
 /// A missing include insertion candidate.
 struct MissingInclude {
   std::string Spelling;
   Header Provider;
 };
 
+/// A missing include finding with per-reference provenance.
+struct MissingIncludeRef {
+  SymbolReference Ref;
+  llvm::SmallVector Providers;
+  SymbolReferenceOrigin Origin = SymbolReferenceOrigin::MainFile;
+  /// Null if the fragment file has multiple direct include sites.
+  const Include *FragmentInclude = nullptr;
+};
+
+/// An include kept alive only by fragment usage.
+struct FragmentDependency {
+  const Include *Preserved = nullptr;
+  llvm::SmallVector Fragments;
+};
+
 /// The result of include-cleaner analysis for one main file.
 struct AnalysisResults {
   std::vector Unused;
   /// Deduplicated insertion plan, e.g. "" paired with the chosen
   /// provider Header.
   std::vector MissingIncludes;
+  /// Per-reference provenance for consumers that need richer diagnostics.
+  std::vector MissingRefs;
+  /// Include-preservation provenance for fragment-only uses.
+  std::vector FragmentDependencies;
 };
 
 /// Analysis configuration shared by include-cleaner consumers.
 struct AnalysisOptions {
   /// No analysis will be performed for headers that satisfy the predicate.
   std::function HeaderFilter;
+  /// A predicate matched against normalized resolved paths, and normalized
+  /// spelled paths as a fallback, to identify direct include fragments.
+  std::function FragmentHeaderFilter;
 };
 
 /// Determine which headers should be inserted or removed from the main file.
diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp 
b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
index cd0b3396bf418..321b67a5787d3 100644
--- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
@@ -8,6 +8,7 @@
 
 #include "clang-include-cleaner/Analysis.h"
 #include "AnalysisInternal.h"
+#include "TypesInternal.h"
 #include "clang-include-cleaner/IncludeSpeller.h"
 #include "clang-include-cleaner/Record.h"
 #include "clang-include-cleaner/Types.h"
@@ -22,9 +23,11 @@
 #include "clang/Tooling/Core/Replacement.h"
 #include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
@@ -32,13 +35,91 @@
 #include "llvm/Support/ErrorHandling.h"
 #include 
 #include 
+#include 
 #include 
 
 namespace clang::include_cleaner {
 
 namespace {
+
+struct ClassifiedReference {
+  SymbolReferenceOrigin Origin;
+  // Null if the fragment file has multiple direct include sites.
+  const Include *FragmentInclude = nullptr;
+};
+
+class FragmentTracker {
+public:
+  FragmentTracker(const Includes &Inc, const SourceManager &SM,
+  const std::function &HeaderFilter)
+  : SM(SM) {
+if (!HeaderFilter)
+  return;
+
+for (const Include &I : Inc.all()) {
+  if (!I.Resolved ||
+  locateInMainFile(I.HashLocation, SM) != MainFileLocation::MainFile) {
+continue;
+  }
+
+  // Match the canonical path first, but fall back to the spelled include
+  // so generated paths can still be configured even when resolution loses
+  // that spelling detail.
+  const llvm::SmallString<128> ResolvedPath =
+  normalizePath(I.Resolved->getName());
+  bool IsFragment = HeaderFilter(ResolvedPath);
+  if (!IsFragment) {
+const llvm::SmallString<128> SpelledPath = normalizePath(I.Spelled);
+if (!SpelledPath.empty()

[llvm-branch-commits] [clang-tools-extra] [include-cleaner] add fragment header analysis (PR #196764)

2026-05-10 Thread Daniil Dudkin via llvm-branch-commits

https://github.com/unterumarmung created 
https://github.com/llvm/llvm-project/pull/196764

None

>From ecbd505fe73b43f3a74b89488cb9e4074caa6863 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin 
Date: Sun, 10 May 2026 01:03:47 +0300
Subject: [PATCH] [include-cleaner] add fragment header analysis

---
 .../include/clang-include-cleaner/Analysis.h  |  29 ++
 .../include-cleaner/lib/Analysis.cpp  | 278 +++
 .../include-cleaner/tool/IncludeCleaner.cpp   |   2 +-
 .../unittests/AnalysisTest.cpp| 325 +-
 4 files changed, 567 insertions(+), 67 deletions(-)

diff --git 
a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h 
b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
index 8e4912fa7bd84..1d28d87c025ca 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
@@ -62,24 +62,53 @@ void walkUsed(llvm::ArrayRef ASTRoots,
   const PragmaIncludes *PI, const Preprocessor &PP,
   UsedSymbolCB CB);
 
+/// A location kind where a symbol reference is observed.
+enum class SymbolReferenceOrigin {
+  MainFile,
+  Preamble,
+  Fragment,
+};
+
 /// A missing include insertion candidate.
 struct MissingInclude {
   std::string Spelling;
   Header Provider;
 };
 
+/// A missing include finding with per-reference provenance.
+struct MissingIncludeRef {
+  SymbolReference Ref;
+  llvm::SmallVector Providers;
+  SymbolReferenceOrigin Origin = SymbolReferenceOrigin::MainFile;
+  /// Null if the fragment file has multiple direct include sites.
+  const Include *FragmentInclude = nullptr;
+};
+
+/// An include kept alive only by fragment usage.
+struct FragmentDependency {
+  const Include *Preserved = nullptr;
+  llvm::SmallVector Fragments;
+};
+
 /// The result of include-cleaner analysis for one main file.
 struct AnalysisResults {
   std::vector Unused;
   /// Deduplicated insertion plan, e.g. "" paired with the chosen
   /// provider Header.
   std::vector MissingIncludes;
+  /// Per-reference provenance for consumers that need richer diagnostics.
+  std::vector MissingRefs;
+  /// Include-preservation provenance for fragment-only uses.
+  std::vector FragmentDependencies;
 };
 
 /// Analysis configuration shared by include-cleaner consumers.
 struct AnalysisOptions {
   /// No analysis will be performed for headers that satisfy the predicate.
   std::function HeaderFilter;
+  /// A predicate matched against normalized resolved paths, and normalized
+  /// spelled paths as a fallback, to identify direct include fragments.
+  std::function FragmentHeaderFilter;
 };
 
 /// Determine which headers should be inserted or removed from the main file.
diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp 
b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
index cd0b3396bf418..321b67a5787d3 100644
--- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
@@ -8,6 +8,7 @@
 
 #include "clang-include-cleaner/Analysis.h"
 #include "AnalysisInternal.h"
+#include "TypesInternal.h"
 #include "clang-include-cleaner/IncludeSpeller.h"
 #include "clang-include-cleaner/Record.h"
 #include "clang-include-cleaner/Types.h"
@@ -22,9 +23,11 @@
 #include "clang/Tooling/Core/Replacement.h"
 #include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
@@ -32,13 +35,91 @@
 #include "llvm/Support/ErrorHandling.h"
 #include 
 #include 
+#include 
 #include 
 
 namespace clang::include_cleaner {
 
 namespace {
+
+struct ClassifiedReference {
+  SymbolReferenceOrigin Origin;
+  // Null if the fragment file has multiple direct include sites.
+  const Include *FragmentInclude = nullptr;
+};
+
+class FragmentTracker {
+public:
+  FragmentTracker(const Includes &Inc, const SourceManager &SM,
+  const std::function &HeaderFilter)
+  : SM(SM) {
+if (!HeaderFilter)
+  return;
+
+for (const Include &I : Inc.all()) {
+  if (!I.Resolved ||
+  locateInMainFile(I.HashLocation, SM) != MainFileLocation::MainFile) {
+continue;
+  }
+
+  // Match the canonical path first, but fall back to the spelled include
+  // so generated paths can still be configured even when resolution loses
+  // that spelling detail.
+  const llvm::SmallString<128> ResolvedPath =
+  normalizePath(I.Resolved->getName());
+  bool IsFragment = HeaderFilter(ResolvedPath);
+  if (!IsFragment) {
+const llvm::SmallString<128> SpelledPath = normalizePath(I.Spelled);
+if (!SpelledPath.empty())
+  IsFragment

[llvm-branch-commits] [clang-tools-extra] [include-cleaner] add fragment header analysis (PR #196764)

2026-05-10 Thread Daniil Dudkin via llvm-branch-commits

https://github.com/unterumarmung ready_for_review 
https://github.com/llvm/llvm-project/pull/196764
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang-tools-extra] [include-cleaner] add fragment header analysis (PR #196764)

2026-05-10 Thread Daniil Dudkin via llvm-branch-commits

unterumarmung wrote:

> [!WARNING]
> This pull request is not mergeable via GitHub because a downstack PR is 
> open. Once all requirements are satisfied, merge this PR as a stack  href="https://app.graphite.com/github/pr/llvm/llvm-project/196764?utm_source=stack-comment-downstack-mergeability-warning";
>  >on Graphite.
> https://graphite.dev/docs/merge-pull-requests";>Learn more

* **#196767** https://app.graphite.com/github/pr/llvm/llvm-project/196767?utm_source=stack-comment-icon";
 target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" 
width="10px" height="10px"/>
* **#196766** https://app.graphite.com/github/pr/llvm/llvm-project/196766?utm_source=stack-comment-icon";
 target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" 
width="10px" height="10px"/>
* **#196765** https://app.graphite.com/github/pr/llvm/llvm-project/196765?utm_source=stack-comment-icon";
 target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" 
width="10px" height="10px"/>
* **#196764** https://app.graphite.com/github/pr/llvm/llvm-project/196764?utm_source=stack-comment-icon";
 target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" 
width="10px" height="10px"/> 👈 https://app.graphite.com/github/pr/llvm/llvm-project/196764?utm_source=stack-comment-view-in-graphite";
 target="_blank">(View in Graphite)
* **#196763** https://app.graphite.com/github/pr/llvm/llvm-project/196763?utm_source=stack-comment-icon";
 target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" 
width="10px" height="10px"/>
* **#196762** https://app.graphite.com/github/pr/llvm/llvm-project/196762?utm_source=stack-comment-icon";
 target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" 
width="10px" height="10px"/>
* **#196761** https://app.graphite.com/github/pr/llvm/llvm-project/196761?utm_source=stack-comment-icon";
 target="_blank">https://static.graphite.dev/graphite-32x32-black.png"; alt="Graphite" 
width="10px" height="10px"/>
* `main`




This stack of pull requests is managed by https://graphite.dev?utm-source=stack-comment";>Graphite. Learn 
more about https://stacking.dev/?utm_source=stack-comment";>stacking.


https://github.com/llvm/llvm-project/pull/196764
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits