diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index ac62dab1b07cd..75ab08de42ea0 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -2241,6 +2241,12 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, if (Style.isJson() || !Style.BreakStringLiterals || !AllowBreak) return nullptr; + // Strings in TypeScript types and dictionary keys can not be broken. + if (Style.isJavaScript() && (Current.is(TT_SelectorName) || + State.Line->startsWith(Keywords.kw_type))) { + return nullptr; + } + // Don't break string literals inside preprocessor directives (except for // #define directives, as their contents are stored in separate lines and // are not affected by this check). diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index bc4c7ff7ba6b3..309326569143d 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -1596,6 +1596,28 @@ TEST_F(FormatTestJS, StringLiteralConcatenation) { "var literal = `xxxxxx ${xxxxxxxxxxxxxxxxxxxxxx + " "xxxxxxxxxxxxxxxxxxxxxx} xxxxxx`;", getGoogleJSStyleWithColumns(14)); + + // Strings in a TypeScript type declaration can't be broken. + verifyFormat("type x =\n" + " 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';", + getGoogleJSStyleWithColumns(20)); + verifyFormat("/* type */ type x =\n" + " 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';", + getGoogleJSStyleWithColumns(20)); + // Dictionary keys can't be broken. Values can be broken. + verifyFormat("var w = {\n" + " 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx':\n" + " 'xxxxxxxxxx' +\n" + " 'xxxxxxxxxx' +\n" + " 'xxxxxxxxxx' +\n" + " 'xxxxxxxxxx' +\n" + " 'xxx',\n" + "};", + "var w = {\n" + " 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx':\n" + " 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n" + "};", + getGoogleJSStyleWithColumns(20)); } TEST_F(FormatTestJS, RegexLiteralClassification) { diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 4348529837129..9ab1eae85f29c 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -2040,6 +2040,25 @@ TEST_F(TokenAnnotatorTest, UnderstandDesignatedInitializers) { EXPECT_TOKEN(Tokens[13], tok::period, TT_DesignatedInitializerPeriod); } +TEST_F(TokenAnnotatorTest, UnderstandsJavaScript) { + auto Annotate = [this](llvm::StringRef Code) { + return annotate(Code, getLLVMStyle(FormatStyle::LK_JavaScript)); + }; + + // Dictionary. + auto Tokens = Annotate("var x = {'x' : 1, 'y' : 2};"); + ASSERT_EQ(Tokens.size(), 14u) << Tokens; + EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_DictLiteral); + EXPECT_TOKEN(Tokens[4], tok::string_literal, TT_SelectorName); + EXPECT_TOKEN(Tokens[5], tok::colon, TT_DictLiteral); + EXPECT_TOKEN(Tokens[8], tok::string_literal, TT_SelectorName); + EXPECT_TOKEN(Tokens[9], tok::colon, TT_DictLiteral); + // Change when we need to annotate these. + EXPECT_BRACE_KIND(Tokens[3], BK_Unknown); + EXPECT_BRACE_KIND(Tokens[11], BK_Unknown); + EXPECT_TOKEN(Tokens[11], tok::r_brace, TT_Unknown); +} + } // namespace } // namespace format } // namespace clang