]> granicus.if.org Git - clang/commitdiff
clang-format: [JS] Improve line-wrapping behavior of template strings.
authorDaniel Jasper <djasper@google.com>
Mon, 20 Feb 2017 14:51:16 +0000 (14:51 +0000)
committerDaniel Jasper <djasper@google.com>
Mon, 20 Feb 2017 14:51:16 +0000 (14:51 +0000)
Specifically, similar to other blocks, clang-format now wraps both
after "${" and before the corresponding "}", if the contained
expression spans multiple lines.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@295663 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Format/ContinuationIndenter.cpp
lib/Format/FormatToken.h
lib/Format/TokenAnnotator.cpp
unittests/Format/FormatTestJS.cpp

index 8a28e630dbcbc1bfdd6032a371d3dd0c5047b8df..00645cd57e7df18ec2c297134e5ae59960b3b49a 100644 (file)
@@ -383,6 +383,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
       Current.FakeLParens.size() > 0 &&
       Current.FakeLParens.back() > prec::Unknown)
     State.Stack.back().NoLineBreak = true;
+  if (Previous.is(TT_TemplateString) && Previous.opensScope())
+    State.Stack.back().NoLineBreak = true;
 
   if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign &&
       Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) &&
@@ -398,7 +400,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
     State.Stack.back().NoLineBreak = true;
   if (Current.isMemberAccess() && Previous.is(tok::r_paren) &&
       (Previous.MatchingParen &&
-       (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) {
+       (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10)))
     // If there is a function call with long parameters, break before trailing
     // calls. This prevents things like:
     //   EXPECT_CALL(SomeLongParameter).Times(
@@ -406,7 +408,6 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
     // We don't want to do this for short parameters as they can just be
     // indexes.
     State.Stack.back().NoLineBreak = true;
-  }
 
   // Don't allow the RHS of an operator to be split over multiple lines unless
   // there is a line-break right after the operator.
@@ -618,7 +619,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
   // If we break after { or the [ of an array initializer, we should also break
   // before the corresponding } or ].
   if (PreviousNonComment &&
-      (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)))
+      (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+       (PreviousNonComment->is(TT_TemplateString) &&
+        PreviousNonComment->opensScope())))
     State.Stack.back().BreakBeforeClosingBrace = true;
 
   if (State.Stack.back().AvoidBinPacking) {
@@ -666,6 +669,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
       return State.Stack[State.Stack.size() - 2].LastSpace;
     return State.FirstIndent;
   }
+  if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
+    return State.Stack[State.Stack.size() - 2].LastSpace;
   if (Current.is(tok::identifier) && Current.Next &&
       Current.Next->is(TT_DictLiteral))
     return State.Stack.back().Indent;
@@ -840,6 +845,11 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
 
   moveStatePastFakeLParens(State, Newline);
   moveStatePastScopeCloser(State);
+  if (Current.is(TT_TemplateString) && Current.opensScope())
+    State.Stack.back().LastSpace =
+        (Current.IsMultiline ? Current.LastLineColumnWidth
+                             : State.Column + Current.ColumnWidth) -
+        strlen("${");
   moveStatePastScopeOpener(State, Newline);
   moveStatePastFakeRParens(State);
 
index 910ddca99840dca9b7c68ce5b8b76d3f05a6992a..3cf95ae125182d48ba7868865a8678c47ef9ba62 100644 (file)
@@ -455,6 +455,8 @@ struct FormatToken {
   /// \brief Returns \c true if this tokens starts a block-type list, i.e. a
   /// list that should be indented with a block indent.
   bool opensBlockOrBlockTypeList(const FormatStyle &Style) const {
+    if (is(TT_TemplateString) && opensScope())
+      return true;
     return is(TT_ArrayInitializerLSquare) ||
            (is(tok::l_brace) &&
             (BlockKind == BK_Block || is(TT_DictLiteral) ||
@@ -463,6 +465,8 @@ struct FormatToken {
 
   /// \brief Same as opensBlockOrBlockTypeList, but for the closing token.
   bool closesBlockOrBlockTypeList(const FormatStyle &Style) const {
+    if (is(TT_TemplateString) && closesScope())
+      return true;
     return MatchingParen && MatchingParen->opensBlockOrBlockTypeList(Style);
   }
 
index 0bf1ca4f4dda6488870495bd93c04cbc32ea8430..a771884eeaf467254b7a800c1f4e774cbc8d268b 100644 (file)
@@ -2536,9 +2536,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
       // https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#A.10
       return false;
     if (Left.isOneOf(Keywords.kw_module, tok::kw_namespace) &&
-        Right.isOneOf(tok::identifier, tok::string_literal)) {
+        Right.isOneOf(tok::identifier, tok::string_literal))
       return false; // must not break in "module foo { ...}"
-    }
+    if (Right.is(TT_TemplateString) && Right.closesScope())
+      return false;
+    if (Left.is(TT_TemplateString) && Left.opensScope())
+      return true;
   }
 
   if (Left.is(tok::at))
index ffd443cc3d763680a5f940ee72309df4ff5df4fb..fe87bf248ff17e130e02a363d689e8440c13de27 100644 (file)
@@ -1421,62 +1421,46 @@ TEST_F(FormatTestJS, TemplateStrings) {
                "         aaaaaaaaaaaaa:${  aaaaaaa. aaaaa} aaaaaaaa`;");
   verifyFormat("var x = someFunction(`${})`)  //\n"
                "            .oooooooooooooooooon();");
-  verifyFormat("var x = someFunction(`${aaaa}${aaaaa(  //\n"
-               "                                   aaaaa)})`);");
+  verifyFormat("var x = someFunction(`${aaaa}${\n"
+               "                               aaaaa(  //\n"
+               "                                   aaaaa)\n"
+               "                             })`);");
 }
 
 TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
-  verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa +  //\n"
-               "                               bbbb}`;",
-               "var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa +  //\n"
-               "                               bbbb}`;");
-  verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${         //\n"
-               "                               aaaaa +  //\n"
-               "                               bbbb}`;",
-               "var f = `aaaaaaaaaaaaaaaaaa: ${         //\n"
+  verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${\n"
                "                               aaaaa +  //\n"
+               "                               bbbb\n"
+               "                             }`;",
+               "var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa +  //\n"
                "                               bbbb}`;");
   verifyFormat("var f = `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${aaaaa +  //\n"
-               "                        bbbb}`;",
+               "  aaaaaaaaaaaaaaaaaa: ${\n"
+               "                        aaaaa +  //\n"
+               "                        bbbb\n"
+               "                      }`;",
                "var f  =  `\n"
                "  aaaaaaaaaaaaaaaaaa: ${   aaaaa  +  //\n"
                "                        bbbb }`;");
   verifyFormat("var f = `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${         //\n"
-               "                        aaaaa +  //\n"
-               "                        bbbb}`;",
-               "var f  =  `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${     //\n"
-               "                        aaaaa  +  //\n"
-               "                        bbbb}`  ;");
-  verifyFormat("var f = `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${someFunction(\n"
-               "                            aaaaa +  //\n"
-               "                            bbbb)}`;",
-               "var f  =  `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${ someFunction  (\n"
-               "                            aaaaa  +   //\n"
-               "                            bbbb)}`;");
-  verifyFormat("var f = `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${  //\n"
+               "  aaaaaaaaaaaaaaaaaa: ${\n"
                "                        someFunction(\n"
                "                            aaaaa +  //\n"
-               "                            bbbb)}`;",
+               "                            bbbb)\n"
+               "                      }`;",
                "var f  =  `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${  //\n"
-               "                        someFunction (\n"
+               "  aaaaaaaaaaaaaaaaaa: ${someFunction (\n"
                "                            aaaaa  +   //\n"
                "                            bbbb)}`;");
+
+  // It might be preferable to wrap before "someFunction".
   verifyFormat("var f = `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${  //\n"
-               "                        someFunction({\n"
+               "  aaaaaaaaaaaaaaaaaa: ${someFunction({\n"
                "                          aaaa: aaaaa,\n"
                "                          bbbb: bbbbb,\n"
                "                        })}`;",
                "var f  =  `\n"
-               "  aaaaaaaaaaaaaaaaaa: ${  //\n"
-               "                        someFunction ({\n"
+               "  aaaaaaaaaaaaaaaaaa: ${someFunction ({\n"
                "                          aaaa:  aaaaa,\n"
                "                          bbbb:  bbbbb,\n"
                "                        })}`;");