[clang] [clang-format] Ignore imports in comments for Java import sorting (PR #177326)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 9 23:58:20 PST 2026
https://github.com/nataliakokoromyti updated https://github.com/llvm/llvm-project/pull/177326
>From e281c4373cbb56cdd226a8bf7f9af681564d5c08 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Thu, 22 Jan 2026 01:35:54 -0800
Subject: [PATCH 01/22] [clang-format] java import sorting should ignore
imports in comments and text blocks
---
clang/lib/Format/Format.cpp | 30 ++++++++++++++++++-
.../unittests/Format/SortImportsTestJava.cpp | 26 ++++++++++++++++
2 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index f0e9aff2fd21a..58dfae897ed0f 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3757,6 +3757,8 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
SmallVector<StringRef> AssociatedCommentLines;
bool FormattingOff = false;
+ bool InBlockComment = false;
+ bool InTextBlock = false;
for (;;) {
auto Pos = Code.find('\n', SearchFrom);
@@ -3769,7 +3771,33 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
else if (isClangFormatOn(Trimmed))
FormattingOff = false;
- if (ImportRegex.match(Line, &Matches)) {
+ // Track block comments (/* ... */)
+ // Check if we're starting a block comment on this line
+ bool IsBlockComment = false;
+ if (Trimmed.starts_with("/*")) {
+ IsBlockComment = true;
+ if (!Trimmed.contains("*/"))
+ InBlockComment = true;
+ }
+ // Check if we're ending a block comment that started on a previous line
+ if (InBlockComment && Trimmed.contains("*/")) {
+ InBlockComment = false;
+ IsBlockComment = true;
+ }
+ // If we're in a multi-line block comment (not the first or last line)
+ if (InBlockComment && !Trimmed.starts_with("/*"))
+ IsBlockComment = true;
+
+ // Track Java text blocks (""" ... """)
+ size_t Count = 0;
+ size_t StartPos = 0;
+ while ((StartPos = Trimmed.find("\"\"\"", StartPos)) != StringRef::npos) {
+ ++Count;
+ StartPos += 3;
+ }
+ if (Count % 2 == 1)
+ InTextBlock = !InTextBlock;
+ if (!IsBlockComment && !InTextBlock && ImportRegex.match(Line, &Matches)) {
if (FormattingOff) {
// If at least one import line has formatting turned off, turn off
// formatting entirely.
diff --git a/clang/unittests/Format/SortImportsTestJava.cpp b/clang/unittests/Format/SortImportsTestJava.cpp
index 26674c75e97b1..9af9d8860fe73 100644
--- a/clang/unittests/Format/SortImportsTestJava.cpp
+++ b/clang/unittests/Format/SortImportsTestJava.cpp
@@ -349,6 +349,32 @@ TEST_F(SortImportsTestJava, NoReplacementsForValidImportsWindows) {
sortIncludes(FmtStyle, Code, GetCodeRange(Code), "input.java").empty());
}
+TEST_F(SortImportsTestJava, DoNotSortImportsInBlockComment) {
+ EXPECT_EQ("/* import org.d;\n"
+ "import org.c;\n"
+ "import org.b; */\n"
+ "import org.a;",
+ sort("/* import org.d;\n"
+ "import org.c;\n"
+ "import org.b; */\n"
+ "import org.a;"));
+}
+
+TEST_F(SortImportsTestJava, DoNotSortImportsInTextBlock) {
+ EXPECT_EQ("String code = \"\"\"\n"
+ " import org.c;\n"
+ " \\\"\"\"\n"
+ " import org.b;\n"
+ "\\\\\"\"\";\n"
+ "import org.a;",
+ sort("String code = \"\"\"\n"
+ " import org.c;\n"
+ " \\\"\"\"\n"
+ " import org.b;\n"
+ "\\\\\"\"\";\n"
+ "import org.a;"));
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
>From bd865fcd182a9e45053713485760f6b616b41b25 Mon Sep 17 00:00:00 2001
From: Natalia Kokoromyti <knatalia at yost-cm-01-imme.stanford.edu>
Date: Sun, 25 Jan 2026 02:07:27 -0800
Subject: [PATCH 02/22] fix
---
clang/lib/Format/Format.cpp | 39 ++++++++-----------
.../unittests/Format/SortImportsTestJava.cpp | 30 +++++++-------
2 files changed, 33 insertions(+), 36 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 58dfae897ed0f..40ce229b9844f 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3743,6 +3743,10 @@ namespace {
const char JavaImportRegexPattern[] =
"^[\t ]*import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;";
+const char JavaTypeDeclRegexPattern[] =
+ "^[\t ]*(public|private|protected|static|final|abstract|sealed|strictfp)?"
+ "[\t ]*(class|interface|enum|record|@interface)[\t ]+";
+
} // anonymous namespace
tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
@@ -3752,13 +3756,12 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
unsigned Prev = 0;
unsigned SearchFrom = 0;
llvm::Regex ImportRegex(JavaImportRegexPattern);
+ llvm::Regex TypeDeclRegex(JavaTypeDeclRegexPattern);
SmallVector<StringRef, 4> Matches;
SmallVector<JavaImportDirective, 16> ImportsInBlock;
SmallVector<StringRef> AssociatedCommentLines;
bool FormattingOff = false;
- bool InBlockComment = false;
- bool InTextBlock = false;
for (;;) {
auto Pos = Code.find('\n', SearchFrom);
@@ -3771,33 +3774,23 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
else if (isClangFormatOn(Trimmed))
FormattingOff = false;
- // Track block comments (/* ... */)
- // Check if we're starting a block comment on this line
+ // Track block comments (/* ... */).
bool IsBlockComment = false;
if (Trimmed.starts_with("/*")) {
IsBlockComment = true;
- if (!Trimmed.contains("*/"))
- InBlockComment = true;
- }
- // Check if we're ending a block comment that started on a previous line
- if (InBlockComment && Trimmed.contains("*/")) {
- InBlockComment = false;
- IsBlockComment = true;
+ // Only skip multi-line comments if we haven't started collecting imports yet.
+ // Comments between imports should be associated with the import below.
+ if (ImportsInBlock.empty()) {
+ Pos = Code.find("*/", SearchFrom + 2);
+ }
}
- // If we're in a multi-line block comment (not the first or last line)
- if (InBlockComment && !Trimmed.starts_with("/*"))
- IsBlockComment = true;
- // Track Java text blocks (""" ... """)
- size_t Count = 0;
- size_t StartPos = 0;
- while ((StartPos = Trimmed.find("\"\"\"", StartPos)) != StringRef::npos) {
- ++Count;
- StartPos += 3;
+ // Check if we've encountered a type declaration - we're past imports.
+ if (!IsBlockComment && TypeDeclRegex.match(Trimmed)) {
+ break;
}
- if (Count % 2 == 1)
- InTextBlock = !InTextBlock;
- if (!IsBlockComment && !InTextBlock && ImportRegex.match(Line, &Matches)) {
+
+ if (!IsBlockComment && ImportRegex.match(Line, &Matches)) {
if (FormattingOff) {
// If at least one import line has formatting turned off, turn off
// formatting entirely.
diff --git a/clang/unittests/Format/SortImportsTestJava.cpp b/clang/unittests/Format/SortImportsTestJava.cpp
index 9af9d8860fe73..1b2b0654cfdae 100644
--- a/clang/unittests/Format/SortImportsTestJava.cpp
+++ b/clang/unittests/Format/SortImportsTestJava.cpp
@@ -360,19 +360,23 @@ TEST_F(SortImportsTestJava, DoNotSortImportsInBlockComment) {
"import org.a;"));
}
-TEST_F(SortImportsTestJava, DoNotSortImportsInTextBlock) {
- EXPECT_EQ("String code = \"\"\"\n"
- " import org.c;\n"
- " \\\"\"\"\n"
- " import org.b;\n"
- "\\\\\"\"\";\n"
- "import org.a;",
- sort("String code = \"\"\"\n"
- " import org.c;\n"
- " \\\"\"\"\n"
- " import org.b;\n"
- "\\\\\"\"\";\n"
- "import org.a;"));
+TEST_F(SortImportsTestJava, StopAtClassDeclaration) {
+ EXPECT_EQ("import org.a;\n"
+ "\n"
+ "class Foo {\n"
+ " String code = \"\"\"\n"
+ " import org.c;\n"
+ " import org.b;\n"
+ " \"\"\";\n"
+ "}",
+ sort("import org.a;\n"
+ "\n"
+ "class Foo {\n"
+ " String code = \"\"\"\n"
+ " import org.c;\n"
+ " import org.b;\n"
+ " \"\"\";\n"
+ "}"));
}
} // end namespace
>From ee14636f8f69aa1e73f160fa584a13cccda9076b Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 26 Jan 2026 00:27:08 -0800
Subject: [PATCH 03/22] fix format
---
clang/lib/Format/Format.cpp | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 40ce229b9844f..07580f7f3311e 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3778,17 +3778,14 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
bool IsBlockComment = false;
if (Trimmed.starts_with("/*")) {
IsBlockComment = true;
- // Only skip multi-line comments if we haven't started collecting imports yet.
- // Comments between imports should be associated with the import below.
- if (ImportsInBlock.empty()) {
+ // Skip block comments before imports start.
+ if (ImportsInBlock.empty())
Pos = Code.find("*/", SearchFrom + 2);
- }
}
- // Check if we've encountered a type declaration - we're past imports.
- if (!IsBlockComment && TypeDeclRegex.match(Trimmed)) {
+ // Check if we've encountered a type declaration.
+ if (!IsBlockComment && TypeDeclRegex.match(Trimmed))
break;
- }
if (!IsBlockComment && ImportRegex.match(Line, &Matches)) {
if (FormattingOff) {
>From d3ceb2220c68629af2457b03c7286127c709889c Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 26 Jan 2026 00:43:41 -0800
Subject: [PATCH 04/22] simplify regexpattern
---
clang/lib/Format/Format.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 07580f7f3311e..dbae8d36b620d 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3744,7 +3744,7 @@ const char JavaImportRegexPattern[] =
"^[\t ]*import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;";
const char JavaTypeDeclRegexPattern[] =
- "^[\t ]*(public|private|protected|static|final|abstract|sealed|strictfp)?"
+ "^[\t ]*(public|private|protected|static|final|abstract)*"
"[\t ]*(class|interface|enum|record|@interface)[\t ]+";
} // anonymous namespace
>From 0446edfe571fba5912fdc04ded62791ff8d78dde Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 2 Feb 2026 02:23:13 -0800
Subject: [PATCH 05/22] rm JavaTypeDeclRegexPattern + handle trimmed.empty() at
top
---
clang/lib/Format/Format.cpp | 41 ++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 21 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index dbae8d36b620d..1879b7c9ee60a 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3743,9 +3743,7 @@ namespace {
const char JavaImportRegexPattern[] =
"^[\t ]*import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;";
-const char JavaTypeDeclRegexPattern[] =
- "^[\t ]*(public|private|protected|static|final|abstract)*"
- "[\t ]*(class|interface|enum|record|@interface)[\t ]+";
+const char JavaPackageRegexPattern[] = "^[\t ]*package[\t ]+[^;]+;";
} // anonymous namespace
@@ -3756,7 +3754,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
unsigned Prev = 0;
unsigned SearchFrom = 0;
llvm::Regex ImportRegex(JavaImportRegexPattern);
- llvm::Regex TypeDeclRegex(JavaTypeDeclRegexPattern);
+ llvm::Regex PackageRegex(JavaPackageRegexPattern);
SmallVector<StringRef, 4> Matches;
SmallVector<JavaImportDirective, 16> ImportsInBlock;
SmallVector<StringRef> AssociatedCommentLines;
@@ -3774,20 +3772,22 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
else if (isClangFormatOn(Trimmed))
FormattingOff = false;
- // Track block comments (/* ... */).
- bool IsBlockComment = false;
- if (Trimmed.starts_with("/*")) {
- IsBlockComment = true;
- // Skip block comments before imports start.
- if (ImportsInBlock.empty())
- Pos = Code.find("*/", SearchFrom + 2);
- }
-
- // Check if we've encountered a type declaration.
- if (!IsBlockComment && TypeDeclRegex.match(Trimmed))
- break;
-
- if (!IsBlockComment && ImportRegex.match(Line, &Matches)) {
+ if (Trimmed.empty()) {
+ // Skip empty lines.
+ } else if (Trimmed.starts_with("//")) {
+ if (!ImportsInBlock.empty())
+ AssociatedCommentLines.push_back(Line);
+ } else if (Trimmed.starts_with("/*")) {
+ auto EndPos = Code.find("*/", SearchFrom + 2);
+ if (EndPos != StringRef::npos) {
+ Line = Code.substr(Prev, EndPos + 2 - Prev);
+ Pos = EndPos + 1;
+ }
+ if (!ImportsInBlock.empty())
+ AssociatedCommentLines.push_back(Line);
+ } else if (PackageRegex.match(Trimmed)) {
+ // Skip package declarations.
+ } else if (ImportRegex.match(Trimmed, &Matches)) {
if (FormattingOff) {
// If at least one import line has formatting turned off, turn off
// formatting entirely.
@@ -3801,9 +3801,8 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
ImportsInBlock.push_back(
{Identifier, Line, Prev, AssociatedCommentLines, IsStatic});
AssociatedCommentLines.clear();
- } else if (!Trimmed.empty() && !ImportsInBlock.empty()) {
- // Associating comments within the imports with the nearest import below
- AssociatedCommentLines.push_back(Line);
+ } else {
+ break;
}
Prev = Pos + 1;
if (Pos == StringRef::npos || Pos + 1 == Code.size())
>From a775a5c401d57208464b356a6e871abf9e6f6cb3 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Sat, 7 Feb 2026 15:11:01 -0800
Subject: [PATCH 06/22] fix regex
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 1879b7c9ee60a..a4ae7bb797119 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3740,10 +3740,10 @@ static void sortJavaImports(const FormatStyle &Style,
namespace {
-const char JavaImportRegexPattern[] =
- "^[\t ]*import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;";
+constexpr StringRef JavaImportRegexPattern(
+"^import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;");
-const char JavaPackageRegexPattern[] = "^[\t ]*package[\t ]+[^;]+;";
+constexpr StringRef JavaPackageRegexPattern("^package[\t ]+");
} // anonymous namespace
>From ddca59c48fccc497b5b4df901a630606d94176a1 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Sat, 7 Feb 2026 15:33:32 -0800
Subject: [PATCH 07/22] fix formatting
---
clang/lib/Format/Format.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index a4ae7bb797119..387711d6af712 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3740,8 +3740,8 @@ static void sortJavaImports(const FormatStyle &Style,
namespace {
-constexpr StringRef JavaImportRegexPattern(
-"^import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;");
+constexpr StringRef
+ JavaImportRegexPattern("^import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;");
constexpr StringRef JavaPackageRegexPattern("^package[\t ]+");
>From 0d1ac13b1d764bfcb0cff9f645c27ee2e75119ef Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Sat, 7 Feb 2026 15:49:32 -0800
Subject: [PATCH 08/22] fix formatting
---
clang/lib/Format/Format.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 387711d6af712..352e7c2723f1f 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3740,7 +3740,7 @@ static void sortJavaImports(const FormatStyle &Style,
namespace {
-constexpr StringRef
+constexpr StringRef
JavaImportRegexPattern("^import[\t ]+(static[\t ]*)?([^\t ]*)[\t ]*;");
constexpr StringRef JavaPackageRegexPattern("^package[\t ]+");
>From 5f93956bed006ab283b674d22395d6fe6e32cb0f Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Sat, 7 Feb 2026 16:04:58 -0800
Subject: [PATCH 09/22] move trimmed.empty() to top
---
clang/lib/Format/Format.cpp | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 352e7c2723f1f..a71da41ed5938 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3766,15 +3766,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
StringRef Line =
Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
- StringRef Trimmed = Line.trim();
- if (isClangFormatOff(Trimmed))
- FormattingOff = true;
- else if (isClangFormatOn(Trimmed))
- FormattingOff = false;
-
- if (Trimmed.empty()) {
- // Skip empty lines.
- } else if (Trimmed.starts_with("//")) {
+ StringRef Trimmed = Line.trim();`r`n if (Trimmed.empty()) {`r`n // Skip empty lines.`r`n } else if (isClangFormatOff(Trimmed)) {`r`n FormattingOff = true;`r`n } else if (isClangFormatOn(Trimmed)) {`r`n FormattingOff = false;`r`n } else if (Trimmed.starts_with("//")) {
if (!ImportsInBlock.empty())
AssociatedCommentLines.push_back(Line);
} else if (Trimmed.starts_with("/*")) {
>From 8b4fbe9019be18989750d8a1d359f91c71ce7fb4 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Sat, 7 Feb 2026 16:05:00 -0800
Subject: [PATCH 10/22] fix newline
---
clang/lib/Format/Format.cpp | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index a71da41ed5938..b9fa503d00c24 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3766,7 +3766,14 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
StringRef Line =
Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
- StringRef Trimmed = Line.trim();`r`n if (Trimmed.empty()) {`r`n // Skip empty lines.`r`n } else if (isClangFormatOff(Trimmed)) {`r`n FormattingOff = true;`r`n } else if (isClangFormatOn(Trimmed)) {`r`n FormattingOff = false;`r`n } else if (Trimmed.starts_with("//")) {
+ StringRef Trimmed = Line.trim();
+ if (Trimmed.empty()) {
+ // Skip empty lines.
+ } else if (isClangFormatOff(Trimmed)) {
+ FormattingOff = true;
+ } else if (isClangFormatOn(Trimmed)) {
+ FormattingOff = false;
+ } else if (Trimmed.starts_with("//")) {
if (!ImportsInBlock.empty())
AssociatedCommentLines.push_back(Line);
} else if (Trimmed.starts_with("/*")) {
>From 5c3449e9780d8f41de71d3f9dbfad2549ac81b5a Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:18:32 -0800
Subject: [PATCH 11/22] keep original comment
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index b9fa503d00c24..ef5f2ef3455b7 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3774,7 +3774,8 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
} else if (isClangFormatOn(Trimmed)) {
FormattingOff = false;
} else if (Trimmed.starts_with("//")) {
- if (!ImportsInBlock.empty())
+ // Associating comments within the imports with the nearest import below.
+ if (HasImport)
AssociatedCommentLines.push_back(Line);
} else if (Trimmed.starts_with("/*")) {
auto EndPos = Code.find("*/", SearchFrom + 2);
>From cb0b54fda6da289fca5c2d33ad82cae702d3a09d Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:19:03 -0800
Subject: [PATCH 12/22] set HasImport
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index ef5f2ef3455b7..cd4736fb8f8bc 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3800,6 +3800,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
IsStatic = true;
ImportsInBlock.push_back(
{Identifier, Line, Prev, AssociatedCommentLines, IsStatic});
+ HasImport = true;
AssociatedCommentLines.clear();
} else {
break;
>From 6474762cc073aa45146cfeb1bf78a0d4c7f9a7be Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:28:47 -0800
Subject: [PATCH 13/22] rm SearchFrom + HasImport decl
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index cd4736fb8f8bc..d770cf31e6a53 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3752,7 +3752,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
StringRef FileName,
tooling::Replacements &Replaces) {
unsigned Prev = 0;
- unsigned SearchFrom = 0;
+ bool HasImport = false;
llvm::Regex ImportRegex(JavaImportRegexPattern);
llvm::Regex PackageRegex(JavaPackageRegexPattern);
SmallVector<StringRef, 4> Matches;
>From c98d19c83c9f6f31ef5930b97c974fda5a0b7082 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:29:11 -0800
Subject: [PATCH 14/22] Update clang/lib/Format/Format.cpp
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index d770cf31e6a53..f0edfc76d8265 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3810,7 +3810,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
break;
SearchFrom = Pos + 1;
}
- if (!ImportsInBlock.empty())
+ if (HasImport)
sortJavaImports(Style, ImportsInBlock, Ranges, FileName, Code, Replaces);
return Replaces;
}
>From c5692e56491192d0d0df331bb97fdc73298428df Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:29:23 -0800
Subject: [PATCH 15/22] Update clang/lib/Format/Format.cpp
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index f0edfc76d8265..ea61b7b0e3ac4 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3778,15 +3778,15 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
if (HasImport)
AssociatedCommentLines.push_back(Line);
} else if (Trimmed.starts_with("/*")) {
- auto EndPos = Code.find("*/", SearchFrom + 2);
- if (EndPos != StringRef::npos) {
- Line = Code.substr(Prev, EndPos + 2 - Prev);
- Pos = EndPos + 1;
- }
- if (!ImportsInBlock.empty())
+ Pos = Code.find("*/", Pos + 2);
+ if (Pos != StringRef::npos)
+ Pos = Code.find('\n', Pos + 2);
+ if (HasImport) {
+ // Extend `Line` for a multiline comment to include all lines the
+ // comment spans.
+ Line = GetLine();
AssociatedCommentLines.push_back(Line);
- } else if (PackageRegex.match(Trimmed)) {
- // Skip package declarations.
+ }
} else if (ImportRegex.match(Trimmed, &Matches)) {
if (FormattingOff) {
// If at least one import line has formatting turned off, turn off
>From 483eb72f4e57a125bc1c14ef610e7e874107cdfd Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:29:35 -0800
Subject: [PATCH 16/22] Update clang/lib/Format/Format.cpp
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index ea61b7b0e3ac4..16178b0d8dbda 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3767,8 +3767,8 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
StringRef Trimmed = Line.trim();
- if (Trimmed.empty()) {
- // Skip empty lines.
+ if (Trimmed.empty() || PackageRegex.match(Trimmed)) {
+ // Skip empty line and package statement.
} else if (isClangFormatOff(Trimmed)) {
FormattingOff = true;
} else if (isClangFormatOn(Trimmed)) {
>From 22de9b38893050a78ac3ba1aaaee623ed02cbbb5 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:29:45 -0800
Subject: [PATCH 17/22] Update clang/lib/Format/Format.cpp
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 16178b0d8dbda..fbcf0421c94ce 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3803,6 +3803,8 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
HasImport = true;
AssociatedCommentLines.clear();
} else {
+ // `Trimmed` is neither empty, nor a comment or a package/import
+ // statement.
break;
}
Prev = Pos + 1;
>From 6894468478f4c976ca0698abe67fe906371073cb Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:29:56 -0800
Subject: [PATCH 18/22] Update clang/unittests/Format/SortImportsTestJava.cpp
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/unittests/Format/SortImportsTestJava.cpp | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/clang/unittests/Format/SortImportsTestJava.cpp b/clang/unittests/Format/SortImportsTestJava.cpp
index 1b2b0654cfdae..68838cd90961d 100644
--- a/clang/unittests/Format/SortImportsTestJava.cpp
+++ b/clang/unittests/Format/SortImportsTestJava.cpp
@@ -350,14 +350,11 @@ TEST_F(SortImportsTestJava, NoReplacementsForValidImportsWindows) {
}
TEST_F(SortImportsTestJava, DoNotSortImportsInBlockComment) {
- EXPECT_EQ("/* import org.d;\n"
- "import org.c;\n"
- "import org.b; */\n"
- "import org.a;",
- sort("/* import org.d;\n"
- "import org.c;\n"
- "import org.b; */\n"
- "import org.a;"));
+ constexpr StringRef Code("/* import org.d;\n"
+ "import org.c;\n"
+ "import org.b; */\n"
+ "import org.a;");
+ EXPECT_EQ(Code, sort(Code));
}
TEST_F(SortImportsTestJava, StopAtClassDeclaration) {
>From 23f28e75d862698066ec44e50e0a454dfd9750d1 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:30:17 -0800
Subject: [PATCH 19/22] Update clang/lib/Format/Format.cpp
Co-authored-by: owenca <owenpiano at gmail.com>
---
clang/lib/Format/Format.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index fbcf0421c94ce..4ccf4f865e1eb 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3810,7 +3810,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
Prev = Pos + 1;
if (Pos == StringRef::npos || Pos + 1 == Code.size())
break;
- SearchFrom = Pos + 1;
+ Prev = Pos + 1;
}
if (HasImport)
sortJavaImports(Style, ImportsInBlock, Ranges, FileName, Code, Replaces);
>From 8b6dca095837fa950d867b07cc2e8961307e1943 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:41:35 -0800
Subject: [PATCH 20/22] rm SearchFrom usage everywhere
---
clang/lib/Format/Format.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 4ccf4f865e1eb..ed3a8e45c2c19 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3762,7 +3762,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
bool FormattingOff = false;
for (;;) {
- auto Pos = Code.find('\n', SearchFrom);
+ auto Pos = Code.find('\n', Prev);
StringRef Line =
Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
@@ -3778,13 +3778,14 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
if (HasImport)
AssociatedCommentLines.push_back(Line);
} else if (Trimmed.starts_with("/*")) {
- Pos = Code.find("*/", Pos + 2);
- if (Pos != StringRef::npos)
- Pos = Code.find('\n', Pos + 2);
+ const auto EndPos = Code.find("*/", Prev + 2);
+ Pos = EndPos != StringRef::npos ? Code.find('\n', EndPos + 2)
+ : StringRef::npos;
if (HasImport) {
// Extend `Line` for a multiline comment to include all lines the
// comment spans.
- Line = GetLine();
+ Line =
+ Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
AssociatedCommentLines.push_back(Line);
}
} else if (ImportRegex.match(Trimmed, &Matches)) {
@@ -3807,7 +3808,6 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
// statement.
break;
}
- Prev = Pos + 1;
if (Pos == StringRef::npos || Pos + 1 == Code.size())
break;
Prev = Pos + 1;
>From 3ade17fbaae4929b78935fbf9357529393cdc628 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:54:12 -0800
Subject: [PATCH 21/22] small refactor
---
clang/lib/Format/Format.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index ed3a8e45c2c19..51e880fb69169 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3759,12 +3759,13 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
SmallVector<JavaImportDirective, 16> ImportsInBlock;
SmallVector<StringRef> AssociatedCommentLines;
- bool FormattingOff = false;
-
- for (;;) {
+ for (bool FormattingOff = false;;) {
auto Pos = Code.find('\n', Prev);
- StringRef Line =
- Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
+ auto GetLine = [&] {
+ return Code.substr(Prev,
+ (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
+ };
+ StringRef Line = GetLine();
StringRef Trimmed = Line.trim();
if (Trimmed.empty() || PackageRegex.match(Trimmed)) {
@@ -3784,8 +3785,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
if (HasImport) {
// Extend `Line` for a multiline comment to include all lines the
// comment spans.
- Line =
- Code.substr(Prev, (Pos != StringRef::npos ? Pos : Code.size()) - Prev);
+ Line = GetLine();
AssociatedCommentLines.push_back(Line);
}
} else if (ImportRegex.match(Trimmed, &Matches)) {
>From d4ded3135d780323870bf50733275bc6b4d65365 Mon Sep 17 00:00:00 2001
From: nataliakokoromyti <nataliakokoromyti at gmail.com>
Date: Mon, 9 Feb 2026 23:57:43 -0800
Subject: [PATCH 22/22] add test that starts with package statement
---
clang/unittests/Format/SortImportsTestJava.cpp | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/clang/unittests/Format/SortImportsTestJava.cpp b/clang/unittests/Format/SortImportsTestJava.cpp
index 68838cd90961d..166540e448627 100644
--- a/clang/unittests/Format/SortImportsTestJava.cpp
+++ b/clang/unittests/Format/SortImportsTestJava.cpp
@@ -376,6 +376,17 @@ TEST_F(SortImportsTestJava, StopAtClassDeclaration) {
"}"));
}
+TEST_F(SortImportsTestJava, SortImportsAfterPackageStatement) {
+ EXPECT_EQ("package org.a;\n"
+ "\n"
+ "import org.a;\n"
+ "import org.b;\n",
+ sort("package org.a;\n"
+ "\n"
+ "import org.b;\n"
+ "import org.a;\n"));
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
More information about the cfe-commits
mailing list