https://github.com/nataliakokoromyti updated https://github.com/llvm/llvm-project/pull/177326
>From e281c4373cbb56cdd226a8bf7f9af681564d5c08 Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <[email protected]> Date: Thu, 22 Jan 2026 01:35:54 -0800 Subject: [PATCH 1/2] [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 <[email protected]> Date: Sun, 25 Jan 2026 02:07:27 -0800 Subject: [PATCH 2/2] 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
