Skip to content

Commit 5db201f

Browse files
authored
[clang-format] Stop breaking unbreakable strings in JS (#66168)
Dictionary literal keys and strings in TypeScript type declarations can not be broken. The problem was pointed out by @alexfh and @e-kud here: https://reviews.llvm.org/D154093#4644512
1 parent d65885a commit 5db201f

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,6 +2241,12 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
22412241
if (Style.isJson() || !Style.BreakStringLiterals || !AllowBreak)
22422242
return nullptr;
22432243

2244+
// Strings in TypeScript types and dictionary keys can not be broken.
2245+
if (Style.isJavaScript() && (Current.is(TT_SelectorName) ||
2246+
State.Line->startsWith(Keywords.kw_type))) {
2247+
return nullptr;
2248+
}
2249+
22442250
// Don't break string literals inside preprocessor directives (except for
22452251
// #define directives, as their contents are stored in separate lines and
22462252
// are not affected by this check).

clang/unittests/Format/FormatTestJS.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,28 @@ TEST_F(FormatTestJS, StringLiteralConcatenation) {
15961596
"var literal = `xxxxxx ${xxxxxxxxxxxxxxxxxxxxxx + "
15971597
"xxxxxxxxxxxxxxxxxxxxxx} xxxxxx`;",
15981598
getGoogleJSStyleWithColumns(14));
1599+
1600+
// Strings in a TypeScript type declaration can't be broken.
1601+
verifyFormat("type x =\n"
1602+
" 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';",
1603+
getGoogleJSStyleWithColumns(20));
1604+
verifyFormat("/* type */ type x =\n"
1605+
" 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';",
1606+
getGoogleJSStyleWithColumns(20));
1607+
// Dictionary keys can't be broken. Values can be broken.
1608+
verifyFormat("var w = {\n"
1609+
" 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx':\n"
1610+
" 'xxxxxxxxxx' +\n"
1611+
" 'xxxxxxxxxx' +\n"
1612+
" 'xxxxxxxxxx' +\n"
1613+
" 'xxxxxxxxxx' +\n"
1614+
" 'xxx',\n"
1615+
"};",
1616+
"var w = {\n"
1617+
" 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx':\n"
1618+
" 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n"
1619+
"};",
1620+
getGoogleJSStyleWithColumns(20));
15991621
}
16001622

16011623
TEST_F(FormatTestJS, RegexLiteralClassification) {

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,25 @@ TEST_F(TokenAnnotatorTest, UnderstandDesignatedInitializers) {
20402040
EXPECT_TOKEN(Tokens[13], tok::period, TT_DesignatedInitializerPeriod);
20412041
}
20422042

2043+
TEST_F(TokenAnnotatorTest, UnderstandsJavaScript) {
2044+
auto Annotate = [this](llvm::StringRef Code) {
2045+
return annotate(Code, getLLVMStyle(FormatStyle::LK_JavaScript));
2046+
};
2047+
2048+
// Dictionary.
2049+
auto Tokens = Annotate("var x = {'x' : 1, 'y' : 2};");
2050+
ASSERT_EQ(Tokens.size(), 14u) << Tokens;
2051+
EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_DictLiteral);
2052+
EXPECT_TOKEN(Tokens[4], tok::string_literal, TT_SelectorName);
2053+
EXPECT_TOKEN(Tokens[5], tok::colon, TT_DictLiteral);
2054+
EXPECT_TOKEN(Tokens[8], tok::string_literal, TT_SelectorName);
2055+
EXPECT_TOKEN(Tokens[9], tok::colon, TT_DictLiteral);
2056+
// Change when we need to annotate these.
2057+
EXPECT_BRACE_KIND(Tokens[3], BK_Unknown);
2058+
EXPECT_BRACE_KIND(Tokens[11], BK_Unknown);
2059+
EXPECT_TOKEN(Tokens[11], tok::r_brace, TT_Unknown);
2060+
}
2061+
20432062
} // namespace
20442063
} // namespace format
20452064
} // namespace clang

0 commit comments

Comments
 (0)