[clang-tools-extra] [include-cleaner] Record #import directives (PR #212596)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 28 12:49:16 PDT 2026


https://github.com/dmaclach created https://github.com/llvm/llvm-project/pull/212596

Detect #import directives during preprocessing and record them with the IncludeDirective::Import type. This ensures Objective-C imports are correctly classified and tracked by the tool.

Also clean up some includes.

>From 0194946bca6182814387c25821e713d4cd0b23cb Mon Sep 17 00:00:00 2001
From: Dave MacLachlan <dmaclach at gmail.com>
Date: Tue, 28 Jul 2026 12:47:18 -0700
Subject: [PATCH] [include-cleaner] Record #import directives

Detect #import directives during preprocessing and record them with the IncludeDirective::Import type. This ensures Objective-C imports are correctly classified and tracked by the tool.

Also clean up some includes.
---
 .../include-cleaner/lib/Record.cpp            | 16 ++++---
 .../include-cleaner/unittests/RecordTest.cpp  | 43 ++++++++++++++++++-
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/include-cleaner/lib/Record.cpp b/clang-tools-extra/include-cleaner/lib/Record.cpp
index 0284d6842e2d2..b549665629fbc 100644
--- a/clang-tools-extra/include-cleaner/lib/Record.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Record.cpp
@@ -18,30 +18,27 @@
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TokenKinds.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Lex/DirectoryLookup.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Tooling/Inclusions/HeaderAnalysis.h"
+#include "clang/Tooling/Inclusions/HeaderIncludes.h"
 #include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
-#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem/UniqueID.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/StringSaver.h"
-#include <algorithm>
 #include <assert.h>
 #include <memory>
 #include <optional>
-#include <set>
 #include <utility>
 #include <vector>
 
@@ -79,6 +76,15 @@ class PPRecorder : public PPCallbacks {
     I.Line = SM.getSpellingLineNumber(Hash);
     I.Spelled = SpelledFilename;
     I.Angled = IsAngled;
+    llvm::StringRef DirectiveName;
+    if (IncludeTok.is(tok::raw_identifier)) {
+      DirectiveName = IncludeTok.getRawIdentifier();
+    } else if (IncludeTok.getIdentifierInfo()) {
+      DirectiveName = IncludeTok.getIdentifierInfo()->getName();
+    }
+    if (DirectiveName == "import") {
+      I.Directive = clang::tooling::IncludeDirective::Import;
+    }
     Recorded.Includes.add(I);
   }
 
diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
index cbf7bae23b365..efd692a2ed35b 100644
--- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
@@ -20,6 +20,7 @@
 #include "clang/Serialization/PCHContainerOperations.h"
 #include "clang/Testing/CommandLineArgs.h"
 #include "clang/Testing/TestAST.h"
+#include "clang/Tooling/Inclusions/HeaderIncludes.h"
 #include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -135,7 +136,7 @@ TEST_F(RecordASTTest, ImplicitTemplates) {
   }
   )cpp";
   Inputs.Code = R"cpp(
-  #include "dispatch.h"  
+  #include "dispatch.h"
   struct MyGetter {
     template <class T> static int get() { return T::value; }
   };
@@ -204,6 +205,46 @@ TEST_F(RecordPPTest, CapturesIncludes) {
   EXPECT_TRUE(M.Angled);
 }
 
+TEST_F(RecordPPTest, CapturesImports) {
+  llvm::Annotations MainFile(R"objc(
+    $H^#import "./header.h"
+    $M^#import <missing.h>
+  )objc");
+  Inputs.Code = MainFile.code();
+  Inputs.ExtraFiles["header.h"] = "";
+  Inputs.ErrorOK = true; // missing header
+  Inputs.ExtraArgs.push_back("-x");
+  Inputs.ExtraArgs.push_back("objective-c");
+  auto AST = build();
+
+  auto Includes = Recorded.Includes.all();
+  ASSERT_EQ(Includes.size(), 2u);
+  EXPECT_THAT(Includes[0], spelled("./header.h"));
+  EXPECT_EQ(Includes[0].Directive, clang::tooling::IncludeDirective::Import);
+  EXPECT_THAT(Includes[1], spelled("missing.h"));
+  EXPECT_EQ(Includes[1].Directive, clang::tooling::IncludeDirective::Import);
+}
+
+TEST_F(RecordPPTest, CapturesMixedDirectives) {
+  llvm::Annotations MainFile(R"objc(
+    $H^#import "./header.h"
+    $I^#include "./header2.h"
+  )objc");
+  Inputs.Code = MainFile.code();
+  Inputs.ExtraFiles["header.h"] = "";
+  Inputs.ExtraFiles["header2.h"] = "";
+  Inputs.ExtraArgs.push_back("-x");
+  Inputs.ExtraArgs.push_back("objective-c");
+  auto AST = build();
+
+  auto Includes = Recorded.Includes.all();
+  ASSERT_EQ(Includes.size(), 2u);
+  EXPECT_THAT(Includes[0], spelled("./header.h"));
+  EXPECT_EQ(Includes[0].Directive, clang::tooling::IncludeDirective::Import);
+  EXPECT_THAT(Includes[1], spelled("./header2.h"));
+  EXPECT_EQ(Includes[1].Directive, clang::tooling::IncludeDirective::Include);
+}
+
 TEST_F(RecordPPTest, CapturesMacroRefs) {
   llvm::Annotations Header(R"cpp(
     #define $def^X 1



More information about the cfe-commits mailing list