Skip to content

Commit b7f5950

Browse files
authored
[clang-format] Handle Java text blocks (llvm#141334)
Fix llvm#61954
1 parent 2d261dc commit b7f5950

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

clang/lib/Format/FormatTokenLexer.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,36 @@ bool FormatTokenLexer::canPrecedeRegexLiteral(FormatToken *Prev) {
694694
return true;
695695
}
696696

697+
void FormatTokenLexer::tryParseJavaTextBlock() {
698+
if (FormatTok->TokenText != "\"\"")
699+
return;
700+
701+
const auto *S = Lex->getBufferLocation();
702+
const auto *End = Lex->getBuffer().end();
703+
704+
if (S == End || *S != '\"')
705+
return;
706+
707+
++S; // Skip the `"""` that begins a text block.
708+
709+
// Find the `"""` that ends the text block.
710+
for (int Count = 0; Count < 3 && S < End; ++S) {
711+
switch (*S) {
712+
case '\\':
713+
Count = -1;
714+
break;
715+
case '\"':
716+
++Count;
717+
break;
718+
default:
719+
Count = 0;
720+
}
721+
}
722+
723+
// Ignore the possibly invalid text block.
724+
resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(S)));
725+
}
726+
697727
// Tries to parse a JavaScript Regex literal starting at the current token,
698728
// if that begins with a slash and is in a location where JavaScript allows
699729
// regex literals. Changes the current token to a regex literal and updates
@@ -1374,6 +1404,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
13741404
FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
13751405
++Column;
13761406
StateStack.push(LexerState::TOKEN_STASHED);
1407+
} else if (Style.isJava() && FormatTok->is(tok::string_literal)) {
1408+
tryParseJavaTextBlock();
13771409
}
13781410

13791411
if (Style.isVerilog() && Tokens.size() > 0 &&

clang/lib/Format/FormatTokenLexer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class FormatTokenLexer {
7272

7373
bool canPrecedeRegexLiteral(FormatToken *Prev);
7474

75+
void tryParseJavaTextBlock();
76+
7577
// Tries to parse a JavaScript Regex literal starting at the current token,
7678
// if that begins with a slash and is in a location where JavaScript allows
7779
// regex literals. Changes the current token to a regex literal and updates

clang/unittests/Format/FormatTestJava.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,63 @@ TEST_F(FormatTestJava, AlignCaseArrows) {
791791
Style);
792792
}
793793

794+
TEST_F(FormatTestJava, TextBlock) {
795+
verifyNoChange("String myStr = \"\"\"\n"
796+
"hello\n"
797+
"there\n"
798+
"\"\"\";");
799+
800+
verifyNoChange("String tb = \"\"\"\n"
801+
" the new\"\"\";");
802+
803+
verifyNoChange("System.out.println(\"\"\"\n"
804+
" This is the first line\n"
805+
" This is the second line\n"
806+
" \"\"\");");
807+
808+
verifyNoChange("void writeHTML() {\n"
809+
" String html = \"\"\" \n"
810+
" <html>\n"
811+
" <p>Hello World.</p>\n"
812+
" </html>\n"
813+
"\"\"\";\n"
814+
" writeOutput(html);\n"
815+
"}");
816+
817+
verifyNoChange("String colors = \"\"\"\t\n"
818+
" red\n"
819+
" green\n"
820+
" blue\"\"\".indent(4);");
821+
822+
verifyNoChange("String code = \"\"\"\n"
823+
" String source = \\\"\"\"\n"
824+
" String message = \"Hello, World!\";\n"
825+
" System.out.println(message);\n"
826+
" \\\"\"\";\n"
827+
" \"\"\";");
828+
829+
verifyNoChange(
830+
"class Outer {\n"
831+
" void printPoetry() {\n"
832+
" String lilacs = \"\"\"\n"
833+
"Passing the apple-tree blows of white and pink in the orchards\n"
834+
"\"\"\";\n"
835+
" System.out.println(lilacs);\n"
836+
" }\n"
837+
"}");
838+
839+
verifyNoChange("String name = \"\"\"\r\n"
840+
" red\n"
841+
" green\n"
842+
" blue\\\n"
843+
" \"\"\";");
844+
845+
verifyFormat("String name = \"\"\"Pat Q. Smith\"\"\";");
846+
847+
verifyNoChange("String name = \"\"\"\n"
848+
" Pat Q. Smith");
849+
}
850+
794851
} // namespace
795852
} // namespace test
796853
} // namespace format

0 commit comments

Comments
 (0)