[clang] b7f5950 - [clang-format] Handle Java text blocks (#141334)
via cfe-commits
cfe-commits at lists.llvm.org
Sun May 25 15:40:50 PDT 2025
Author: Owen Pan
Date: 2025-05-25T15:40:45-07:00
New Revision: b7f5950bb3b97eac979925a3bbf015530c26962e
URL: https://github.com/llvm/llvm-project/commit/b7f5950bb3b97eac979925a3bbf015530c26962e
DIFF: https://github.com/llvm/llvm-project/commit/b7f5950bb3b97eac979925a3bbf015530c26962e.diff
LOG: [clang-format] Handle Java text blocks (#141334)
Fix #61954
Added:
Modified:
clang/lib/Format/FormatTokenLexer.cpp
clang/lib/Format/FormatTokenLexer.h
clang/unittests/Format/FormatTestJava.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 864486a9b878d..4cc4f5f22db0d 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -694,6 +694,36 @@ bool FormatTokenLexer::canPrecedeRegexLiteral(FormatToken *Prev) {
return true;
}
+void FormatTokenLexer::tryParseJavaTextBlock() {
+ if (FormatTok->TokenText != "\"\"")
+ return;
+
+ const auto *S = Lex->getBufferLocation();
+ const auto *End = Lex->getBuffer().end();
+
+ if (S == End || *S != '\"')
+ return;
+
+ ++S; // Skip the `"""` that begins a text block.
+
+ // Find the `"""` that ends the text block.
+ for (int Count = 0; Count < 3 && S < End; ++S) {
+ switch (*S) {
+ case '\\':
+ Count = -1;
+ break;
+ case '\"':
+ ++Count;
+ break;
+ default:
+ Count = 0;
+ }
+ }
+
+ // Ignore the possibly invalid text block.
+ resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(S)));
+}
+
// Tries to parse a JavaScript Regex literal starting at the current token,
// if that begins with a slash and is in a location where JavaScript allows
// regex literals. Changes the current token to a regex literal and updates
@@ -1374,6 +1404,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
++Column;
StateStack.push(LexerState::TOKEN_STASHED);
+ } else if (Style.isJava() && FormatTok->is(tok::string_literal)) {
+ tryParseJavaTextBlock();
}
if (Style.isVerilog() && Tokens.size() > 0 &&
diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h
index 105847b126e20..026383db1fe6c 100644
--- a/clang/lib/Format/FormatTokenLexer.h
+++ b/clang/lib/Format/FormatTokenLexer.h
@@ -72,6 +72,8 @@ class FormatTokenLexer {
bool canPrecedeRegexLiteral(FormatToken *Prev);
+ void tryParseJavaTextBlock();
+
// Tries to parse a JavaScript Regex literal starting at the current token,
// if that begins with a slash and is in a location where JavaScript allows
// regex literals. Changes the current token to a regex literal and updates
diff --git a/clang/unittests/Format/FormatTestJava.cpp b/clang/unittests/Format/FormatTestJava.cpp
index e01c1d6d7e684..ca5aba043b932 100644
--- a/clang/unittests/Format/FormatTestJava.cpp
+++ b/clang/unittests/Format/FormatTestJava.cpp
@@ -791,6 +791,63 @@ TEST_F(FormatTestJava, AlignCaseArrows) {
Style);
}
+TEST_F(FormatTestJava, TextBlock) {
+ verifyNoChange("String myStr = \"\"\"\n"
+ "hello\n"
+ "there\n"
+ "\"\"\";");
+
+ verifyNoChange("String tb = \"\"\"\n"
+ " the new\"\"\";");
+
+ verifyNoChange("System.out.println(\"\"\"\n"
+ " This is the first line\n"
+ " This is the second line\n"
+ " \"\"\");");
+
+ verifyNoChange("void writeHTML() {\n"
+ " String html = \"\"\" \n"
+ " <html>\n"
+ " <p>Hello World.</p>\n"
+ " </html>\n"
+ "\"\"\";\n"
+ " writeOutput(html);\n"
+ "}");
+
+ verifyNoChange("String colors = \"\"\"\t\n"
+ " red\n"
+ " green\n"
+ " blue\"\"\".indent(4);");
+
+ verifyNoChange("String code = \"\"\"\n"
+ " String source = \\\"\"\"\n"
+ " String message = \"Hello, World!\";\n"
+ " System.out.println(message);\n"
+ " \\\"\"\";\n"
+ " \"\"\";");
+
+ verifyNoChange(
+ "class Outer {\n"
+ " void printPoetry() {\n"
+ " String lilacs = \"\"\"\n"
+ "Passing the apple-tree blows of white and pink in the orchards\n"
+ "\"\"\";\n"
+ " System.out.println(lilacs);\n"
+ " }\n"
+ "}");
+
+ verifyNoChange("String name = \"\"\"\r\n"
+ " red\n"
+ " green\n"
+ " blue\\\n"
+ " \"\"\";");
+
+ verifyFormat("String name = \"\"\"Pat Q. Smith\"\"\";");
+
+ verifyNoChange("String name = \"\"\"\n"
+ " Pat Q. Smith");
+}
+
} // namespace
} // namespace test
} // namespace format
More information about the cfe-commits
mailing list