[PATCH] D47193: clang-format: [JS] do not wrap before any `is`.

2018-05-22 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
Herald added subscribers: cfe-commits, klimek.

`is` type annotations can occur at any nesting level. For example:

  function x() {
return function y(): a is B { ... };
  }

Breaking before the `is` above breaks TypeScript parsing the code. This
change prevents the wrap.


Repository:
  rC Clang

https://reviews.llvm.org/D47193

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1164,7 +1164,15 @@
   verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
   verifyFormat("some['a']['b']", getGoogleJSStyleWithColumns(10));
   verifyFormat("x = (a['a']\n"
-   "  ['b']);", getGoogleJSStyleWithColumns(10));
+   "  ['b']);",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("function f() {\n"
+   "  return foo.bar(\n"
+   "  (param): param is {\n"
+   "a: SomeType\n"
+   "  }&ABC => 1)\n"
+   "}",
+   getGoogleJSStyleWithColumns(25));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2958,7 +2958,7 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
-if (Right.NestingLevel == 0 && Right.is(Keywords.kw_is))
+if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
   return Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1164,7 +1164,15 @@
   verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
   verifyFormat("some['a']['b']", getGoogleJSStyleWithColumns(10));
   verifyFormat("x = (a['a']\n"
-   "  ['b']);", getGoogleJSStyleWithColumns(10));
+   "  ['b']);",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("function f() {\n"
+   "  return foo.bar(\n"
+   "  (param): param is {\n"
+   "a: SomeType\n"
+   "  }&ABC => 1)\n"
+   "}",
+   getGoogleJSStyleWithColumns(25));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2958,7 +2958,7 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
-if (Right.NestingLevel == 0 && Right.is(Keywords.kw_is))
+if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
   return Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47193: clang-format: [JS] do not wrap before any `is`.

2018-05-22 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC332968: clang-format: [JS] do not wrap before any `is`. 
(authored by mprobst, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D47193?vs=147978&id=147979#toc

Repository:
  rC Clang

https://reviews.llvm.org/D47193

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2958,7 +2958,7 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
-if (Right.NestingLevel == 0 && Right.is(Keywords.kw_is))
+if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
   return Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None;
Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1164,7 +1164,15 @@
   verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
   verifyFormat("some['a']['b']", getGoogleJSStyleWithColumns(10));
   verifyFormat("x = (a['a']\n"
-   "  ['b']);", getGoogleJSStyleWithColumns(10));
+   "  ['b']);",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("function f() {\n"
+   "  return foo.bar(\n"
+   "  (param): param is {\n"
+   "a: SomeType\n"
+   "  }&ABC => 1)\n"
+   "}",
+   getGoogleJSStyleWithColumns(25));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {


Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2958,7 +2958,7 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
-if (Right.NestingLevel == 0 && Right.is(Keywords.kw_is))
+if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
   return Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None;
Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1164,7 +1164,15 @@
   verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
   verifyFormat("some['a']['b']", getGoogleJSStyleWithColumns(10));
   verifyFormat("x = (a['a']\n"
-   "  ['b']);", getGoogleJSStyleWithColumns(10));
+   "  ['b']);",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("function f() {\n"
+   "  return foo.bar(\n"
+   "  (param): param is {\n"
+   "a: SomeType\n"
+   "  }&ABC => 1)\n"
+   "}",
+   getGoogleJSStyleWithColumns(25));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49797: [clang-format] Indent after breaking Javadoc annotated line

2018-07-26 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: lib/Format/BreakableToken.cpp:526
+  0, Content[LineIndex].find_first_of(Blanks));
+  if (FirstWord == "@param")
+return Style.ContinuationIndentWidth;

Shouldn't this check the set above?



Comment at: unittests/Format/FormatTestComments.cpp:3109
+TEST_F(FormatTestComments, IndentsLongJavadocAnnotatedLines) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Java);
+  Style.ColumnLimit = 60;

add a test using `@return` or `@type`?



Comment at: unittests/Format/FormatTestComments.cpp:3154
+
+  EXPECT_EQ("/**\n"
+" * @param l1 long1\n"

do we already have a test that `@param {oh noes this is really long} foo` isn't 
broken?


Repository:
  rC Clang

https://reviews.llvm.org/D49797



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49797: [clang-format] Indent after breaking Javadoc annotated line

2018-07-27 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: unittests/Format/FormatTestComments.cpp:3109
+TEST_F(FormatTestComments, IndentsLongJavadocAnnotatedLines) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Java);
+  Style.ColumnLimit = 60;

mprobst wrote:
> add a test using `@return` or `@type`?
as discussed, make sure to test for LK_JavaScript, because that affects this 
with comment pragmas (that we should probably disable).


Repository:
  rC Clang

https://reviews.llvm.org/D49797



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49797: [clang-format] Indent after breaking Javadoc annotated line

2018-07-27 Thread Martin Probst via Phabricator via cfe-commits
mprobst accepted this revision.
mprobst added inline comments.
This revision is now accepted and ready to land.



Comment at: lib/Format/Format.cpp:814
+// by qualified identifiers.
+GoogleStyle.CommentPragmas = "(taze:|^/[ 
\t]*<|@see|@exports|@module|@mods)";
 GoogleStyle.MaxEmptyLinesToKeep = 3;

`@exports` isn't really a thing in JS, it is really `@export`.

But more generally, where do you get stuff like `@module` from, and what is it 
supposed to do?

google3 has `@pintomodule`, `@mods` and `@modName`, but I don't think those 
need special treatment.

I think I'd drop everything except the `@see` here.


Repository:
  rC Clang

https://reviews.llvm.org/D49797



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49797: [clang-format] Indent after breaking Javadoc annotated line

2018-07-27 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: lib/Format/Format.cpp:814
+// by qualified identifiers.
+GoogleStyle.CommentPragmas = "(taze:|^/[ 
\t]*<|@see|@exports|@module|@mods)";
 GoogleStyle.MaxEmptyLinesToKeep = 3;

krasimir wrote:
> mprobst wrote:
> > `@exports` isn't really a thing in JS, it is really `@export`.
> > 
> > But more generally, where do you get stuff like `@module` from, and what is 
> > it supposed to do?
> > 
> > google3 has `@pintomodule`, `@mods` and `@modName`, but I don't think those 
> > need special treatment.
> > 
> > I think I'd drop everything except the `@see` here.
> There were existing tests having these.
> I can find a reference to `@exports` and `@module` here: 
> http://usejsdoc.org/tags-exports.html.
> I think that in general if the annotation is supposed to only have the form 
> `@tag some-long-path-separated-machine-readable-identifier`, that should be 
> left on a single line.
> For `@mods`, I vaguely remember adding that test case while fixing a bug that 
> it shouldn't be broken.
> Still, happy to remove these and we'll wait to see if anyone complains.
Please don't change the test code that uses `@export`, that's a commonly used 
Closure Compiler annotation.

JSDoc isn't really a consistently applied standard, over time implementations 
have diverged a lot, so I'm afraid those docs might not apply to Closure 
Compiler's use of JSDoc. I don't think this hurts here, but I wouldn't expect 
anybody getting much use out of this either, so it might be cleaner to drop.


Repository:
  rC Clang

https://reviews.llvm.org/D49797



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50177: clang-format: fix a crash in comment wraps.

2018-08-02 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.

Previously, clang-format would crash if it tried to wrap an overlong
single line comment, because two parts of the code inserted a break in
the same location.

  /** heregoesalongcommentwithnospace */

This wasn't previously noticed as it could only trigger for an overlong
single line comment that did have no breaking opportunities except for a
whitespace at the very beginning.

This also introduces a check for JavaScript to not ever wrap a comment
before an opening curly brace:

  /** @mods {donotbreakbeforethecurly} */

This is because some machinery parsing these tags sometimes supports
breaks before a possible `{`, but in some other cases does not.
Previously clang-format was careful never to wrap a line with certain
tags on it. The better solution is to specifically disable wrapping
before the problematic token: this allows wrapping and aligning comments
but still avoids the problem.


Repository:
  rC Clang

https://reviews.llvm.org/D50177

Files:
  lib/Format/BreakableToken.cpp
  unittests/Format/FormatTestComments.cpp
  unittests/Format/FormatTestJS.cpp

Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -191,31 +191,32 @@
 
   // Break a single line long jsdoc comment pragma.
   EXPECT_EQ("/**\n"
-" * @returns\n"
-" * {string}\n"
-" * jsdoc line 12\n"
+" * @returns {string} jsdoc line 12\n"
 " */",
 format("/** @returns {string} jsdoc line 12 */",
getGoogleJSStyleWithColumns(20)));
-
   EXPECT_EQ("/**\n"
-" * @returns\n"
-" * {string}\n"
+" * @returns {string}\n"
 " * jsdoc line 12\n"
 " */",
+format("/** @returns {string} jsdoc line 12 */",
+   getGoogleJSStyleWithColumns(25)));
+
+  EXPECT_EQ("/**\n"
+" * @returns {string} jsdoc line 12\n"
+" */",
 format("/** @returns {string} jsdoc line 12  */",
getGoogleJSStyleWithColumns(20)));
 
   // FIXME: this overcounts the */ as a continuation of the 12 when breaking.
   // Related to the FIXME in BreakableBlockComment::getRangeLength.
   EXPECT_EQ("/**\n"
-" * @returns\n"
-" * {string}\n"
-" * jsdoc line\n"
+" * @returns {string}\n"
+" * jsdoc line line\n"
 " * 12\n"
 " */",
-format("/** @returns {string} jsdoc line 12*/",
-   getGoogleJSStyleWithColumns(20)));
+format("/** @returns {string} jsdoc line line 12*/",
+   getGoogleJSStyleWithColumns(25)));
 
   // Fix a multiline jsdoc comment ending in a comment pragma.
   EXPECT_EQ("/**\n"
@@ -2038,27 +2039,32 @@
 
 TEST_F(FormatTestJS, JSDocAnnotations) {
   verifyFormat("/**\n"
-   " * @exports\n"
-   " * {this.is.a.long.path.to.a.Type}\n"
+   " * @exports {this.is.a.long.path.to.a.Type}\n"
" */",
"/**\n"
" * @exports {this.is.a.long.path.to.a.Type}\n"
" */",
getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
-   " * @mods\n"
-   " * {this.is.a.long.path.to.a.Type}\n"
+   " * @mods {this.is.a.long.path.to.a.Type}\n"
+   " */",
+   "/**\n"
+   " * @mods {this.is.a.long.path.to.a.Type}\n"
+   " */",
+   getGoogleJSStyleWithColumns(20));
+  verifyFormat("/**\n"
+   " * @mods {this.is.a.long.path.to.a.Type}\n"
" */",
"/**\n"
" * @mods {this.is.a.long.path.to.a.Type}\n"
" */",
getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
-   " * @param\n"
-   " * {this.is.a.long.path.to.a.Type}\n"
+   " * @param {canWrap\n"
+   " * onSpace}\n"
" */",
"/**\n"
-   " * @param {this.is.a.long.path.to.a.Type}\n"
+   " * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
@@ -2083,8 +2089,7 @@
 "  /**\n"
 "   * long long long\n"
 "   * long\n"
-"   * @param\n"
-"   * {this.is.a.long.path.to.a.Type}\n"
+"   * @param {this.is.a.long.path.to.a.Type}\n"
 "   * a\n"
 "   * long long long\n"
 "   * long long\n"
Index: unittests/Format/FormatTestComments.cpp
===
--- unittests/Format/FormatTestComments.cpp
+++ unittests/Format/FormatTestComments.cpp
@@

[PATCH] D50177: clang-format: fix a crash in comment wraps.

2018-08-02 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL338706: clang-format: fix a crash in comment wraps. 
(authored by mprobst, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D50177

Files:
  cfe/trunk/lib/Format/BreakableToken.cpp
  cfe/trunk/unittests/Format/FormatTestComments.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp

Index: cfe/trunk/lib/Format/BreakableToken.cpp
===
--- cfe/trunk/lib/Format/BreakableToken.cpp
+++ cfe/trunk/lib/Format/BreakableToken.cpp
@@ -67,10 +67,11 @@
  unsigned ContentStartColumn,
  unsigned ColumnLimit,
  unsigned TabWidth,
- encoding::Encoding Encoding) {
-  LLVM_DEBUG(llvm::dbgs() << "Comment split: \"" << Text << ", " << ColumnLimit
-  << "\", Content start: " << ContentStartColumn
-  << "\n");
+ encoding::Encoding Encoding,
+ const FormatStyle &Style) {
+  LLVM_DEBUG(llvm::dbgs() << "Comment split: \"" << Text
+  << "\", Column limit: " << ColumnLimit
+  << ", Content start: " << ContentStartColumn << "\n");
   if (ColumnLimit <= ContentStartColumn + 1)
 return BreakableToken::Split(StringRef::npos, 0);
 
@@ -95,6 +96,13 @@
   if (SpaceOffset != StringRef::npos &&
   kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
 SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  // In JavaScript, some @tags can be followed by {, and machinery that parses
+  // these comments will fail to understand the comment if followed by a line
+  // break. So avoid ever breaking before a {.
+  if (Style.Language == FormatStyle::LK_JavaScript &&
+  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
+  Text[SpaceOffset + 1] == '{')
+SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
 
   if (SpaceOffset == StringRef::npos ||
   // Don't break at leading whitespace.
@@ -109,6 +117,12 @@
 Blanks, std::max(MaxSplitBytes, FirstNonWhitespace));
   }
   if (SpaceOffset != StringRef::npos && SpaceOffset != 0) {
+// adaptStartOfLine will break after lines starting with /** if the comment
+// is broken anywhere. Avoid emitting this break twice here.
+// Example: in /** longtextcomesherethatbreaks */ (with ColumnLimit 20) will
+// insert a break after /**, so this code must not insert the same break.
+if (SpaceOffset == 1 && Text[SpaceOffset - 1] == '*')
+  return BreakableToken::Split(StringRef::npos, 0);
 StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(Blanks);
 StringRef AfterCut = Text.substr(SpaceOffset).ltrim(Blanks);
 return BreakableToken::Split(BeforeCut.size(),
@@ -260,7 +274,7 @@
 return Split(StringRef::npos, 0);
   return getCommentSplit(Content[LineIndex].substr(TailOffset),
  ContentStartColumn, ColumnLimit, Style.TabWidth,
- Encoding);
+ Encoding, Style);
 }
 
 void BreakableComment::compressWhitespace(
@@ -620,6 +634,8 @@
 if (DelimitersOnNewline) {
   // Since we're breaking at index 1 below, the break position and the
   // break length are the same.
+  // Note: this works because getCommentSplit is careful never to split at
+  // the beginning of a line.
   size_t BreakLength = Lines[0].substr(1).find_first_not_of(Blanks);
   if (BreakLength != StringRef::npos)
 insertBreak(LineIndex, 0, Split(1, BreakLength), /*ContentIndent=*/0,
Index: cfe/trunk/unittests/Format/FormatTestComments.cpp
===
--- cfe/trunk/unittests/Format/FormatTestComments.cpp
+++ cfe/trunk/unittests/Format/FormatTestComments.cpp
@@ -1254,6 +1254,12 @@
" */",
getLLVMStyleWithColumns(20)));
 
+  // This reproduces a crashing bug where both adaptStartOfLine and
+  // getCommentSplit were trying to wrap after the "/**".
+  EXPECT_EQ("/** multilineblockcommentwithnowrapopportunity */",
+format("/** multilineblockcommentwithnowrapopportunity */",
+   getLLVMStyleWithColumns(20)));
+
   EXPECT_EQ("/*\n"
 "\n"
 "\n"
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -191,31 +191,32 @@
 
   // Break a single line long jsdoc comment pragma.
   EXPECT_EQ("/**\n"
-" * @returns\n"
-" * {string}\n"
-" * jsdoc line 12\n"
+

[PATCH] D50230: clang-format: [JS] don't break comments before any '{'

2018-08-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.

Previously, clang-format would avoid breaking before the first `{`
found, but then happily break before subsequent '{'s on the line. This
change fixes that by looking for the first location that has no opening
curly, if any.


Repository:
  rC Clang

https://reviews.llvm.org/D50230

Files:
  lib/Format/BreakableToken.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",
Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -99,7 +99,7 @@
   // In JavaScript, some @tags can be followed by {, and machinery that parses
   // these comments will fail to understand the comment if followed by a line
   // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
+  while (Style.Language == FormatStyle::LK_JavaScript &&
   SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
   Text[SpaceOffset + 1] == '{')
 SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",
Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -99,7 +99,7 @@
   // In JavaScript, some @tags can be followed by {, and machinery that parses
   // these comments will fail to understand the comment if followed by a line
   // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
+  while (Style.Language == FormatStyle::LK_JavaScript &&
   SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
   Text[SpaceOffset + 1] == '{')
 SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D50230: clang-format: [JS] don't break comments before any '{'

2018-08-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 158946.
mprobst added a comment.

Also handle multiple numbered list tokens.


Repository:
  rC Clang

https://reviews.llvm.org/D50230

Files:
  lib/Format/BreakableToken.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",
Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,19 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
-  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
-  Text[SpaceOffset + 1] == '{')
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  while (SpaceOffset != StringRef::npos) {
+// Do not split before a number followed by a dot: this would be 
interpreted
+// as a numbered list, which would prevent re-flowing in subsequent passes.
+if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+// In JavaScript, some @tags can be followed by {, and machinery that 
parses
+// these comments will fail to understand the comment if followed by a line
+// break. So avoid ever breaking before a {.
+else if (Style.Language == FormatStyle::LK_JavaScript &&
+ SpaceOffset + 1 < Text.size() && Text[SpaceOffset + 1] == '{')
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  }
 
   if (SpaceOffset == StringRef::npos ||
   // Don't break at leading whitespace.


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",
Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,19 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
-  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
-  Text[SpaceOffset + 1] == '{')
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  while (SpaceOffset != StringRef::npos) {
+// Do not split before a number followed by a dot: this would be interpreted
+// as a numbered list, which would prevent re-flow

[PATCH] D50230: clang-format: [JS] don't break comments before any '{'

2018-08-03 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC338837: clang-format: [JS] don't break comments before 
any '{' (authored by mprobst, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D50230?vs=158946&id=158957#toc

Repository:
  rC Clang

https://reviews.llvm.org/D50230

Files:
  lib/Format/BreakableToken.cpp
  unittests/Format/FormatTestJS.cpp


Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,19 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
-  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
-  Text[SpaceOffset + 1] == '{')
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  while (SpaceOffset != StringRef::npos) {
+// Do not split before a number followed by a dot: this would be 
interpreted
+// as a numbered list, which would prevent re-flowing in subsequent passes.
+if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+// In JavaScript, some @tags can be followed by {, and machinery that 
parses
+// these comments will fail to understand the comment if followed by a line
+// break. So avoid ever breaking before a {.
+else if (Style.Language == FormatStyle::LK_JavaScript &&
+ SpaceOffset + 1 < Text.size() && Text[SpaceOffset + 1] == '{')
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  }
 
   if (SpaceOffset == StringRef::npos ||
   // Don't break at leading whitespace.
Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",


Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,19 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
-  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
-  Text[SpaceOffset + 1] == '{')
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  while (SpaceOffset != StringRef::npos) {
+// Do not split before a number followed by a dot: this would be interpreted
+// as a numbered list, which would prevent re-flowing in subsequent passes.
+if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+// In JavaScript, some @tags can be followed by {, and machinery that parses
+// these comments will fail to understand the comment if followed by a line
+// break. So avoid ever breaking before a {.
+else if (Style.Language == FormatStyle::LK_JavaScript &&
+ SpaceOffset + 1 < Text.size() && Text[SpaceOffset + 1] == '{')
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOf

[PATCH] D50249: clang-format: [JS] don't break comments before any '{'

2018-08-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
Herald added a subscriber: cfe-commits.

Previously, clang-format would avoid breaking before the first `{`
found, but then happily break before subsequent '{'s on the line. This
change fixes that by looking for the first location that has no opening
curly, if any.

This fixes the original commit by correcting the loop condition.

This reverts commit 66dc646e09b795b943668179c33d09da71a3b6bc.


Repository:
  rC Clang

https://reviews.llvm.org/D50249

Files:
  lib/Format/BreakableToken.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",
Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,21 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
-  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
-  Text[SpaceOffset + 1] == '{')
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  while (SpaceOffset != StringRef::npos) {
+// Do not split before a number followed by a dot: this would be 
interpreted
+// as a numbered list, which would prevent re-flowing in subsequent passes.
+if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+// In JavaScript, some @tags can be followed by {, and machinery that 
parses
+// these comments will fail to understand the comment if followed by a line
+// break. So avoid ever breaking before a {.
+else if (Style.Language == FormatStyle::LK_JavaScript &&
+ SpaceOffset + 1 < Text.size() && Text[SpaceOffset + 1] == '{')
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+else
+  break;
+  }
 
   if (SpaceOffset == StringRef::npos ||
   // Don't break at leading whitespace.


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",
Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,21 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyl

[PATCH] D50249: clang-format: [JS] don't break comments before any '{'

2018-08-03 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC338890: clang-format: [JS] don't break comments before 
any '{' (authored by mprobst, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D50249?vs=158993&id=159001#toc

Repository:
  rC Clang

https://reviews.llvm.org/D50249

Files:
  lib/Format/BreakableToken.cpp
  unittests/Format/FormatTestJS.cpp


Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,21 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
-  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
-  Text[SpaceOffset + 1] == '{')
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  while (SpaceOffset != StringRef::npos) {
+// Do not split before a number followed by a dot: this would be 
interpreted
+// as a numbered list, which would prevent re-flowing in subsequent passes.
+if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+// In JavaScript, some @tags can be followed by {, and machinery that 
parses
+// these comments will fail to understand the comment if followed by a line
+// break. So avoid ever breaking before a {.
+else if (Style.Language == FormatStyle::LK_JavaScript &&
+ SpaceOffset + 1 < Text.size() && Text[SpaceOffset + 1] == '{')
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+else
+  break;
+  }
 
   if (SpaceOffset == StringRef::npos ||
   // Don't break at leading whitespace.
Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2067,6 +2067,14 @@
" * @param {canWrap onSpace}\n"
" */",
getGoogleJSStyleWithColumns(20));
+  // make sure clang-format doesn't break before *any* '{'
+  verifyFormat("/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   "/**\n"
+   " * @lala {lala {lalala\n"
+   " */\n",
+   getGoogleJSStyleWithColumns(20));
   verifyFormat("/**\n"
" * @see http://very/very/long/url/is/long\n";
" */",


Index: lib/Format/BreakableToken.cpp
===
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -90,19 +90,21 @@
 
   StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
 
-  // Do not split before a number followed by a dot: this would be interpreted
-  // as a numbered list, which would prevent re-flowing in subsequent passes.
   static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\.");
-  if (SpaceOffset != StringRef::npos &&
-  kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
-  // In JavaScript, some @tags can be followed by {, and machinery that parses
-  // these comments will fail to understand the comment if followed by a line
-  // break. So avoid ever breaking before a {.
-  if (Style.Language == FormatStyle::LK_JavaScript &&
-  SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() &&
-  Text[SpaceOffset + 1] == '{')
-SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+  while (SpaceOffset != StringRef::npos) {
+// Do not split before a number followed by a dot: this would be interpreted
+// as a numbered list, which would prevent re-flowing in subsequent passes.
+if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks)))
+  SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+// In JavaScript, some @tags can be followed by {, and machinery that parses
+// these comments will fail to understand the comment if followed by a line
+// break. So avoid ever breaking before a {.
+else if (Style.Language == FormatStyle::LK_JavaScript &&
+ SpaceOffset + 1 < Text.size() && Text[SpaceOffset + 1] == '{')
+  SpaceOffset = Text.find

[PATCH] D43440: clang-format: [JS] fix `of` detection.

2018-02-18 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: djasper.
Herald added a subscriber: klimek.

`of` is only a keyword when after an identifier, but not when after
an actual keyword.

Before:

  return of (a, b, c);

After:

  return of(a, b, c);


Repository:
  rC Clang

https://reviews.llvm.org/D43440

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -294,6 +294,7 @@
   verifyFormat("x.for = 1;");
   verifyFormat("x.of();");
   verifyFormat("of(null);");
+  verifyFormat("return of(null);");
   verifyFormat("import {of} from 'x';");
   verifyFormat("x.in();");
   verifyFormat("x.let();");
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2496,7 +2496,7 @@
  // (e.g. as "const x of y" in a for loop), or after a destructuring
  // operation (const [x, y] of z, const {a, b} of c).
  (Left.is(Keywords.kw_of) && Left.Previous &&
-  (Left.Previous->Tok.getIdentifierInfo() ||
+  (Left.Previous->Tok.is(tok::identifier) ||
Left.Previous->isOneOf(tok::r_square, tok::r_brace &&
 (!Left.Previous || !Left.Previous->is(tok::period)))
   return true;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -294,6 +294,7 @@
   verifyFormat("x.for = 1;");
   verifyFormat("x.of();");
   verifyFormat("of(null);");
+  verifyFormat("return of(null);");
   verifyFormat("import {of} from 'x';");
   verifyFormat("x.in();");
   verifyFormat("x.let();");
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2496,7 +2496,7 @@
  // (e.g. as "const x of y" in a for loop), or after a destructuring
  // operation (const [x, y] of z, const {a, b} of c).
  (Left.is(Keywords.kw_of) && Left.Previous &&
-  (Left.Previous->Tok.getIdentifierInfo() ||
+  (Left.Previous->Tok.is(tok::identifier) ||
Left.Previous->isOneOf(tok::r_square, tok::r_brace &&
 (!Left.Previous || !Left.Previous->is(tok::period)))
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43440: clang-format: [JS] fix `of` detection.

2018-02-19 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL325489: clang-format: [JS] fix `of` detection. (authored by 
mprobst, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D43440

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2496,7 +2496,7 @@
  // (e.g. as "const x of y" in a for loop), or after a destructuring
  // operation (const [x, y] of z, const {a, b} of c).
  (Left.is(Keywords.kw_of) && Left.Previous &&
-  (Left.Previous->Tok.getIdentifierInfo() ||
+  (Left.Previous->Tok.is(tok::identifier) ||
Left.Previous->isOneOf(tok::r_square, tok::r_brace &&
 (!Left.Previous || !Left.Previous->is(tok::period)))
   return true;
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -294,6 +294,7 @@
   verifyFormat("x.for = 1;");
   verifyFormat("x.of();");
   verifyFormat("of(null);");
+  verifyFormat("return of(null);");
   verifyFormat("import {of} from 'x';");
   verifyFormat("x.in();");
   verifyFormat("x.let();");


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2496,7 +2496,7 @@
  // (e.g. as "const x of y" in a for loop), or after a destructuring
  // operation (const [x, y] of z, const {a, b} of c).
  (Left.is(Keywords.kw_of) && Left.Previous &&
-  (Left.Previous->Tok.getIdentifierInfo() ||
+  (Left.Previous->Tok.is(tok::identifier) ||
Left.Previous->isOneOf(tok::r_square, tok::r_brace &&
 (!Left.Previous || !Left.Previous->is(tok::period)))
   return true;
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -294,6 +294,7 @@
   verifyFormat("x.for = 1;");
   verifyFormat("x.of();");
   verifyFormat("of(null);");
+  verifyFormat("return of(null);");
   verifyFormat("import {of} from 'x';");
   verifyFormat("x.in();");
   verifyFormat("x.let();");
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33640: clang-format: [JS] fix indenting bound functions.

2017-05-29 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

The previous fix to force build style wrapping if the previous token is a 
closing parenthesis broke a peculiar pattern where users parenthesize the 
function declaration in a bind call:

  fn((function() { ... }).bind(this));

This restores the previous behaviour by reverting that change, but narrowing 
the special case for unindenting closing parentheses to those followed by 
semicolons and opening braces, i.e. immediate calls and function declarations.


https://reviews.llvm.org/D33640

Files:
  lib/Format/ContinuationIndenter.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -207,7 +207,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn && // Current.TokenText == "bind" &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -676,7 +676,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi 
or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // ) {
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -207,7 +207,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn && // Current.TokenText == "bind" &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -676,7 +676,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // ) {
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33640: clang-format: [JS] fix indenting bound functions.

2017-05-29 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 100588.
mprobst added a comment.

- fix comment


https://reviews.llvm.org/D33640

Files:
  lib/Format/ContinuationIndenter.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -207,7 +207,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn && // Current.TokenText == "bind" &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -676,7 +676,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi 
or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // function foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // }
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -207,7 +207,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn && // Current.TokenText == "bind" &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -676,7 +676,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // function foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // }
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33640: clang-format: [JS] fix indenting bound functions.

2017-05-29 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 100589.
mprobst added a comment.

- fix comment


https://reviews.llvm.org/D33640

Files:
  lib/Format/ContinuationIndenter.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -207,7 +207,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -676,7 +676,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi 
or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // function foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // }
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -207,7 +207,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -676,7 +676,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // function foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // }
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33640: clang-format: [JS] fix indenting bound functions.

2017-05-29 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL304135: clang-format: [JS] fix indenting bound functions. 
(authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D33640?vs=100589&id=100591#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D33640

Files:
  cfe/trunk/lib/Format/ContinuationIndenter.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: cfe/trunk/lib/Format/ContinuationIndenter.cpp
===
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp
@@ -215,7 +215,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -689,7 +689,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi 
or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // function foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // }
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;


Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -717,6 +717,11 @@
"  bar();\n"
"}.bind(this));");
 
+  verifyFormat("SomeFunction((function() {\n"
+   "   foo();\n"
+   "   bar();\n"
+   " }).bind(this));");
+
   // FIXME: This is bad, we should be wrapping before "function() {".
   verifyFormat("someFunction(function() {\n"
"  doSomething();  // break\n"
Index: cfe/trunk/lib/Format/ContinuationIndenter.cpp
===
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp
@@ -215,7 +215,7 @@
   // ...
   //   }.bind(...));
   // FIXME: We should find a more generic solution to this problem.
-  !(State.Column <= NewLineColumn && Previous.isNot(tok::r_paren) &&
+  !(State.Column <= NewLineColumn &&
 Style.Language == FormatStyle::LK_JavaScript))
 return true;
 
@@ -689,7 +689,18 @@
   return State.Stack[State.Stack.size() - 2].LastSpace;
 return State.FirstIndent;
   }
-  if (Current.is(tok::r_paren) && State.Stack.size() > 1)
+  // Indent a closing parenthesis at the previous level if followed by a semi or
+  // opening brace. This allows indentations such as:
+  // foo(
+  //   a,
+  // );
+  // function foo(
+  //   a,
+  // ) {
+  //   code(); //
+  // }
+  if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+  (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
 return State.Stack[State.Stack.size() - 2].LastSpace;
   if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
 return State.Stack[State.Stack.size() - 2].LastSpace;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33714: clang-format: [JS] improve calculateBraceType heuristic

2017-05-31 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

calculateBraceTypes decides for braced init for empty brace pairs ({}). In 
context of a function declaration, this incorrectly classifies empty function 
or method bodies as braced inits, leading to missing wraps:

  class C {
foo() {}[bar]() {}
  }

Where could should have wrapped after "}". This change adds another piece of 
contextual information in that braces following closing parentheses must always 
be the opening braces of function blocks. This fixes brace detection for 
methods immediately followed by brackets (computed property declarations), but 
also curlies.


https://reviews.llvm.org/D33714

Files:
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -368,6 +368,9 @@
 // members in a type member list, which would normally trigger 
BK_Block.
 // In both cases, this must be parsed as an inline braced init.
 Tok->BlockKind = BK_BracedInit;
+  else if (PrevTok && PrevTok->is(tok::r_paren))
+// `) { ... }` can only occur in function or method declarations.
+Tok->BlockKind = BK_Block;
   else
 Tok->BlockKind = BK_Unknown;
   LBraceStack.push_back(Tok);
@@ -391,6 +394,8 @@
   // BlockKind later if we parse a braced list (where all blocks
   // inside are by default braced lists), or when we explicitly detect
   // blocks (for example while parsing lambdas).
+  // TODO(martinprobst): Some of these do not apply to JS, e.g. "} {"
+  // can never be a braced list in JS.
   ProbablyBracedList =
   (Style.Language == FormatStyle::LK_JavaScript &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -368,6 +368,9 @@
 // members in a type member list, which would normally trigger BK_Block.
 // In both cases, this must be parsed as an inline braced init.
 Tok->BlockKind = BK_BracedInit;
+  else if (PrevTok && PrevTok->is(tok::r_paren))
+// `) { ... }` can only occur in function or method declarations.
+Tok->BlockKind = BK_Block;
   else
 Tok->BlockKind = BK_Unknown;
   LBraceStack.push_back(Tok);
@@ -391,6 +394,8 @@
   // BlockKind later if we parse a braced list (where all blocks
 

[PATCH] D33714: clang-format: [JS] improve calculateBraceType heuristic

2017-05-31 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 100839.
mprobst added a comment.

TODO => FIXME


https://reviews.llvm.org/D33714

Files:
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -368,6 +368,9 @@
 // members in a type member list, which would normally trigger 
BK_Block.
 // In both cases, this must be parsed as an inline braced init.
 Tok->BlockKind = BK_BracedInit;
+  else if (PrevTok && PrevTok->is(tok::r_paren))
+// `) { ... }` can only occur in function or method declarations.
+Tok->BlockKind = BK_Block;
   else
 Tok->BlockKind = BK_Unknown;
   LBraceStack.push_back(Tok);
@@ -391,6 +394,8 @@
   // BlockKind later if we parse a braced list (where all blocks
   // inside are by default braced lists), or when we explicitly detect
   // blocks (for example while parsing lambdas).
+  // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
+  // braced list in JS.
   ProbablyBracedList =
   (Style.Language == FormatStyle::LK_JavaScript &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -368,6 +368,9 @@
 // members in a type member list, which would normally trigger BK_Block.
 // In both cases, this must be parsed as an inline braced init.
 Tok->BlockKind = BK_BracedInit;
+  else if (PrevTok && PrevTok->is(tok::r_paren))
+// `) { ... }` can only occur in function or method declarations.
+Tok->BlockKind = BK_Block;
   else
 Tok->BlockKind = BK_Unknown;
   LBraceStack.push_back(Tok);
@@ -391,6 +394,8 @@
   // BlockKind later if we parse a braced list (where all blocks
   // inside are by default braced lists), or when we explicitly detect
   // blocks (for example while parsing lambdas).
+  // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
+  // braced list in JS.
   ProbablyBracedList =
   (Style.Language == FormatStyle::LK_JavaScript &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33714: clang-format: [JS] improve calculateBraceType heuristic

2017-05-31 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 100840.
mprobst added a comment.

- restrict to JS, C++ actually wants this.


https://reviews.llvm.org/D33714

Files:
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -360,16 +360,21 @@
 
 switch (Tok->Tok.getKind()) {
 case tok::l_brace:
-  if (Style.Language == FormatStyle::LK_JavaScript && PrevTok &&
-  PrevTok->is(tok::colon))
-// A colon indicates this code is in a type, or a braced list following
-// a label in an object literal ({a: {b: 1}}).
-// The code below could be confused by semicolons between the 
individual
-// members in a type member list, which would normally trigger 
BK_Block.
-// In both cases, this must be parsed as an inline braced init.
-Tok->BlockKind = BK_BracedInit;
-  else
+  if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
+if (PrevTok->is(tok::colon))
+  // A colon indicates this code is in a type, or a braced list
+  // following a label in an object literal ({a: {b: 1}}). The code
+  // below could be confused by semicolons between the individual
+  // members in a type member list, which would normally trigger
+  // BK_Block. In both cases, this must be parsed as an inline braced
+  // init.
+  Tok->BlockKind = BK_BracedInit;
+else if (PrevTok->is(tok::r_paren))
+  // `) { ... }` can only occur in function or method declarations.
+  Tok->BlockKind = BK_Block;
+  } else {
 Tok->BlockKind = BK_Unknown;
+  }
   LBraceStack.push_back(Tok);
   break;
 case tok::r_brace:
@@ -391,6 +396,8 @@
   // BlockKind later if we parse a braced list (where all blocks
   // inside are by default braced lists), or when we explicitly detect
   // blocks (for example while parsing lambdas).
+  // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
+  // braced list in JS.
   ProbablyBracedList =
   (Style.Language == FormatStyle::LK_JavaScript &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -360,16 +360,21 @@
 
 switch (Tok->Tok.getKind()) {
 case tok::l_brace:
-  if (Style.Language == Forma

[PATCH] D33714: clang-format: [JS] improve calculateBraceType heuristic

2017-05-31 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL304290: clang-format: [JS] improve calculateBraceType 
heuristic (authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D33714?vs=100840&id=100841#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D33714

Files:
  cfe/trunk/lib/Format/UnwrappedLineParser.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -360,16 +360,21 @@
 
 switch (Tok->Tok.getKind()) {
 case tok::l_brace:
-  if (Style.Language == FormatStyle::LK_JavaScript && PrevTok &&
-  PrevTok->is(tok::colon))
-// A colon indicates this code is in a type, or a braced list following
-// a label in an object literal ({a: {b: 1}}).
-// The code below could be confused by semicolons between the 
individual
-// members in a type member list, which would normally trigger 
BK_Block.
-// In both cases, this must be parsed as an inline braced init.
-Tok->BlockKind = BK_BracedInit;
-  else
+  if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
+if (PrevTok->is(tok::colon))
+  // A colon indicates this code is in a type, or a braced list
+  // following a label in an object literal ({a: {b: 1}}). The code
+  // below could be confused by semicolons between the individual
+  // members in a type member list, which would normally trigger
+  // BK_Block. In both cases, this must be parsed as an inline braced
+  // init.
+  Tok->BlockKind = BK_BracedInit;
+else if (PrevTok->is(tok::r_paren))
+  // `) { }` can only occur in function or method declarations in JS.
+  Tok->BlockKind = BK_Block;
+  } else {
 Tok->BlockKind = BK_Unknown;
+  }
   LBraceStack.push_back(Tok);
   break;
 case tok::r_brace:
@@ -391,6 +396,8 @@
   // BlockKind later if we parse a braced list (where all blocks
   // inside are by default braced lists), or when we explicitly detect
   // blocks (for example while parsing lambdas).
+  // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
+  // braced list in JS.
   ProbablyBracedList =
   (Style.Language == FormatStyle::LK_JavaScript &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,


Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -474,9 +474,8 @@
"(function f() {\n"
"  var x = 1;\n"
"}());\n");
-  // Known issue: this should wrap after {}, but calculateBraceTypes
-  // misclassifies the first braces as a BK_BracedInit.
-  verifyFormat("function aFunction(){} {\n"
+  verifyFormat("function aFunction() {}\n"
+   "{\n"
"  let x = 1;\n"
"  console.log(x);\n"
"}\n");
@@ -1233,6 +1232,10 @@
   verifyFormat("class C {\n  x: string = 12;\n}");
   verifyFormat("class C {\n  x(): string => 12;\n}");
   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
+  verifyFormat("class C {\n"
+   "  foo() {}\n"
+   "  [bar]() {}\n"
+   "}\n");
   verifyFormat("class C {\n  private x: string = 12;\n}");
   verifyFormat("class C {\n  private static x: string = 12;\n}");
   verifyFormat("class C {\n  static x(): string {\nreturn 'asd';\n  }\n}");
Index: cfe/trunk/lib/

[PATCH] D33857: Correctly Indent Nested JavaScript Literals.

2017-06-06 Thread Martin Probst via Phabricator via cfe-commits
mprobst accepted this revision.
mprobst added a comment.
This revision is now accepted and ready to land.

LGTM


Repository:
  rL LLVM

https://reviews.llvm.org/D33857



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33857: Correctly Indent Nested JavaScript Literals.

2017-06-06 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL304791: clang-format: [JS] Correctly Indent Nested 
JavaScript Literals. (authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D33857?vs=101296&id=101547#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D33857

Files:
  cfe/trunk/lib/Format/ContinuationIndenter.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/ContinuationIndenter.cpp
===
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp
@@ -1036,8 +1036,8 @@
 State.Stack.back().NestedBlockIndent);
   if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
 if (Current.opensBlockOrBlockTypeList(Style)) {
-  NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
-  NewIndent = std::min(State.Column + 2, NewIndent);
+  NewIndent = Style.IndentWidth +
+  std::min(State.Column, State.Stack.back().NestedBlockIndent);
 } else {
   NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
 }
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1869,5 +1869,44 @@
   verifyFormat("squared **= 2;");
 }
 
+TEST_F(FormatTestJS, NestedLiterals) {
+  FormatStyle FourSpaces = getGoogleJSStyleWithColumns(15);
+  FourSpaces.IndentWidth = 4;
+  verifyFormat("var l = [\n"
+   "[\n"
+   "1,\n"
+   "],\n"
+   "];", FourSpaces);
+  verifyFormat("var l = [\n"
+   "{\n"
+   "1: 1,\n"
+   "},\n"
+   "];", FourSpaces);
+  verifyFormat("someFunction(\n"
+   "p1,\n"
+   "[\n"
+   "1,\n"
+   "],\n"
+   ");", FourSpaces);
+  verifyFormat("someFunction(\n"
+   "p1,\n"
+   "{\n"
+   "1: 1,\n"
+   "},\n"
+   ");", FourSpaces);
+  verifyFormat("var o = {\n"
+   "1: 1,\n"
+   "2: {\n"
+   "3: 3,\n"
+   "},\n"
+   "};", FourSpaces);
+  verifyFormat("var o = {\n"
+   "1: 1,\n"
+   "2: [\n"
+   "3,\n"
+   "],\n"
+   "};", FourSpaces);
+}
+
 } // end namespace tooling
 } // end namespace clang


Index: cfe/trunk/lib/Format/ContinuationIndenter.cpp
===
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp
@@ -1036,8 +1036,8 @@
 State.Stack.back().NestedBlockIndent);
   if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
 if (Current.opensBlockOrBlockTypeList(Style)) {
-  NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
-  NewIndent = std::min(State.Column + 2, NewIndent);
+  NewIndent = Style.IndentWidth +
+  std::min(State.Column, State.Stack.back().NestedBlockIndent);
 } else {
   NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
 }
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1869,5 +1869,44 @@
   verifyFormat("squared **= 2;");
 }
 
+TEST_F(FormatTestJS, NestedLiterals) {
+  FormatStyle FourSpaces = getGoogleJSStyleWithColumns(15);
+  FourSpaces.IndentWidth = 4;
+  verifyFormat("var l = [\n"
+   "[\n"
+   "1,\n"
+   "],\n"
+   "];", FourSpaces);
+  verifyFormat("var l = [\n"
+   "{\n"
+   "1: 1,\n"
+   "},\n"
+   "];", FourSpaces);
+  verifyFormat("someFunction(\n"
+   "p1,\n"
+   "[\n"
+   "1,\n"
+   "],\n"
+   ");", FourSpaces);
+  verifyFormat("someFunction(\n"
+   "p1,\n"
+   "{\n"
+   "1: 1,\n"
+   "},\n"
+   ");", FourSpaces);
+  verifyFormat("var o = {\n"
+   "1: 1,\n"
+   "2: {\n"
+   "3: 3,\n"
+   "},\n"
+   "};", FourSpaces);
+  verifyFormat("var o = {\n"
+   "1: 1,\n"
+   "2: [\n"
+   "3,\n"
+   "],\n"
+   "};", FourSpaces);
+}
+
 } // end na

[PATCH] D48030: clang-format: [JS] strict prop init annotation.

2018-06-11 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.

TypeScript uses the `!` token for strict property initialization
assertions, as in:

  class X {
strictPropAsserted!: string;
  }

Previously, clang-format would wrap between the `!` and the `:` for
overly long lines. This patch fixes that by generally preventing the
wrap in that location.


Repository:
  rC Clang

https://reviews.llvm.org/D48030

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1540,6 +1540,15 @@
"}");
 }
 
+TEST_F(FormatTestJS, StrictPropInitWrap) {
+  const FormatStyle &Style = getGoogleJSStyleWithColumns(22);
+  verifyFormat("class X {\n"
+   "  strictPropInitField!:\n"
+   "   string;\n"
+   "}",
+   Style);
+}
+
 TEST_F(FormatTestJS, InterfaceDeclarations) {
   verifyFormat("interface I {\n"
"  x: string;\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2981,7 +2981,7 @@
   // We deal with this case later by detecting an entry
   // following a closing paren of this submessage.
 }
-
+
 // If this is an entry immediately following a submessage, it will be
 // preceded by a closing paren of that submessage, like in:
 // left---.  .---right
@@ -3027,6 +3027,9 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
+// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
+if (Left.is(tok::exclaim) && Right.is(tok::colon))
+  return false;
 if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1540,6 +1540,15 @@
"}");
 }
 
+TEST_F(FormatTestJS, StrictPropInitWrap) {
+  const FormatStyle &Style = getGoogleJSStyleWithColumns(22);
+  verifyFormat("class X {\n"
+   "  strictPropInitField!:\n"
+   "   string;\n"
+   "}",
+   Style);
+}
+
 TEST_F(FormatTestJS, InterfaceDeclarations) {
   verifyFormat("interface I {\n"
"  x: string;\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2981,7 +2981,7 @@
   // We deal with this case later by detecting an entry
   // following a closing paren of this submessage.
 }
-
+
 // If this is an entry immediately following a submessage, it will be
 // preceded by a closing paren of that submessage, like in:
 // left---.  .---right
@@ -3027,6 +3027,9 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
+// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
+if (Left.is(tok::exclaim) && Right.is(tok::colon))
+  return false;
 if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48030: clang-format: [JS] strict prop init annotation.

2018-06-11 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 150770.
mprobst added a comment.

fix typo in test


Repository:
  rC Clang

https://reviews.llvm.org/D48030

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1540,6 +1540,15 @@
"}");
 }
 
+TEST_F(FormatTestJS, StrictPropInitWrap) {
+  const FormatStyle &Style = getGoogleJSStyleWithColumns(22);
+  verifyFormat("class X {\n"
+   "  strictPropInitField!:\n"
+   "  string;\n"
+   "}",
+   Style);
+}
+
 TEST_F(FormatTestJS, InterfaceDeclarations) {
   verifyFormat("interface I {\n"
"  x: string;\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2981,7 +2981,7 @@
   // We deal with this case later by detecting an entry
   // following a closing paren of this submessage.
 }
-
+
 // If this is an entry immediately following a submessage, it will be
 // preceded by a closing paren of that submessage, like in:
 // left---.  .---right
@@ -3027,6 +3027,9 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
+// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
+if (Left.is(tok::exclaim) && Right.is(tok::colon))
+  return false;
 if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1540,6 +1540,15 @@
"}");
 }
 
+TEST_F(FormatTestJS, StrictPropInitWrap) {
+  const FormatStyle &Style = getGoogleJSStyleWithColumns(22);
+  verifyFormat("class X {\n"
+   "  strictPropInitField!:\n"
+   "  string;\n"
+   "}",
+   Style);
+}
+
 TEST_F(FormatTestJS, InterfaceDeclarations) {
   verifyFormat("interface I {\n"
"  x: string;\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2981,7 +2981,7 @@
   // We deal with this case later by detecting an entry
   // following a closing paren of this submessage.
 }
-
+
 // If this is an entry immediately following a submessage, it will be
 // preceded by a closing paren of that submessage, like in:
 // left---.  .---right
@@ -3027,6 +3027,9 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
+// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
+if (Left.is(tok::exclaim) && Right.is(tok::colon))
+  return false;
 if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48030: clang-format: [JS] strict prop init annotation.

2018-06-11 Thread Martin Probst via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rL334415: clang-format: [JS] strict prop init annotation. 
(authored by mprobst, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D48030

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2981,7 +2981,7 @@
   // We deal with this case later by detecting an entry
   // following a closing paren of this submessage.
 }
-
+
 // If this is an entry immediately following a submessage, it will be
 // preceded by a closing paren of that submessage, like in:
 // left---.  .---right
@@ -3027,6 +3027,9 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
+// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
+if (Left.is(tok::exclaim) && Right.is(tok::colon))
+  return false;
 if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1540,6 +1540,15 @@
"}");
 }
 
+TEST_F(FormatTestJS, StrictPropInitWrap) {
+  const FormatStyle &Style = getGoogleJSStyleWithColumns(22);
+  verifyFormat("class X {\n"
+   "  strictPropInitField!:\n"
+   "  string;\n"
+   "}",
+   Style);
+}
+
 TEST_F(FormatTestJS, InterfaceDeclarations) {
   verifyFormat("interface I {\n"
"  x: string;\n"


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2981,7 +2981,7 @@
   // We deal with this case later by detecting an entry
   // following a closing paren of this submessage.
 }
-
+
 // If this is an entry immediately following a submessage, it will be
 // preceded by a closing paren of that submessage, like in:
 // left---.  .---right
@@ -3027,6 +3027,9 @@
   return false;
 if (Left.is(TT_JsTypeColon))
   return true;
+// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
+if (Left.is(tok::exclaim) && Right.is(tok::colon))
+  return false;
 if (Right.is(Keywords.kw_is))
   return false;
 if (Left.is(Keywords.kw_in))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1540,6 +1540,15 @@
"}");
 }
 
+TEST_F(FormatTestJS, StrictPropInitWrap) {
+  const FormatStyle &Style = getGoogleJSStyleWithColumns(22);
+  verifyFormat("class X {\n"
+   "  strictPropInitField!:\n"
+   "  string;\n"
+   "}",
+   Style);
+}
+
 TEST_F(FormatTestJS, InterfaceDeclarations) {
   verifyFormat("interface I {\n"
"  x: string;\n"
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59527: [clang-format] Don't insert break between JS template string and tag identifier

2019-03-19 Thread Martin Probst via Phabricator via cfe-commits
mprobst accepted this revision.
mprobst added a comment.
This revision is now accepted and ready to land.

LGTM.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59527/new/

https://reviews.llvm.org/D59527



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59527: [clang-format] Don't insert break between JS template string and tag identifier

2019-03-19 Thread Martin Probst via Phabricator via cfe-commits
mprobst closed this revision.
mprobst added a comment.

Landed as r356447.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59527/new/

https://reviews.llvm.org/D59527



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59292: [clang-format] messes up indentation when using JavaScript private fields and methods

2019-03-19 Thread Martin Probst via Phabricator via cfe-commits
mprobst accepted this revision.
mprobst added a comment.
This revision is now accepted and ready to land.

Actually I'll fix the nits.




Comment at: clang/docs/ReleaseNotes.rst:174
 
-- ...
+- Add support for correct indenting of private fields and methods in 
Javascript.
 

Honestly, I think we don't really do release notes for clang-format. Revert 
this, or I'll drop it when committing your change.



Comment at: clang/lib/Format/FormatToken.h:66
   TYPE(JsTypeOptionalQuestion) 
\
+  TYPE(JsPrivateIdentifier)
\
   TYPE(LambdaArrow)
\

nit: please keep alpha sorted, i.e. before Js[T]


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59292/new/

https://reviews.llvm.org/D59292



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59292: [clang-format] messes up indentation when using JavaScript private fields and methods

2019-03-19 Thread Martin Probst via Phabricator via cfe-commits
mprobst closed this revision.
mprobst added a comment.

Landed in r356449, thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59292/new/

https://reviews.llvm.org/D59292



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52535: clang-format: [JS] space after parameter naming.

2018-09-26 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: mboehme.

Previously:

  foo(/*bar=*/baz);

Now:

  foo(/*bar=*/ baz);

The run-in parameter naming comment is not intended in JS.


Repository:
  rC Clang

https://reviews.llvm.org/D52535

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2304,5 +2304,9 @@
  "};"));
 }
 
+TEST_F(FormatTestJS, ParameterNamingComment) {
+  verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
Right.MatchingParen->BlockKind != BK_Block))
 return !Style.Cpp11BracedListStyle;
   if (Left.is(TT_BlockComment))
-return !Left.TokenText.endswith("=*/");
+// No whitespace in x(/*foo=*/1), except for JavaScript.
+return Style.Language == FormatStyle::LK_JavaScript ||
+   !Left.TokenText.endswith("=*/");
   if (Right.is(tok::l_paren)) {
 if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
 (Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2304,5 +2304,9 @@
  "};"));
 }
 
+TEST_F(FormatTestJS, ParameterNamingComment) {
+  verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
Right.MatchingParen->BlockKind != BK_Block))
 return !Style.Cpp11BracedListStyle;
   if (Left.is(TT_BlockComment))
-return !Left.TokenText.endswith("=*/");
+// No whitespace in x(/*foo=*/1), except for JavaScript.
+return Style.Language == FormatStyle::LK_JavaScript ||
+   !Left.TokenText.endswith("=*/");
   if (Right.is(tok::l_paren)) {
 if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
 (Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52535: clang-format: [JS] space after parameter naming.

2018-09-26 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL343080: clang-format: [JS] space after parameter naming. 
(authored by mprobst, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D52535

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
Right.MatchingParen->BlockKind != BK_Block))
 return !Style.Cpp11BracedListStyle;
   if (Left.is(TT_BlockComment))
-return !Left.TokenText.endswith("=*/");
+// No whitespace in x(/*foo=*/1), except for JavaScript.
+return Style.Language == FormatStyle::LK_JavaScript ||
+   !Left.TokenText.endswith("=*/");
   if (Right.is(tok::l_paren)) {
 if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
 (Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -2304,5 +2304,9 @@
  "};"));
 }
 
+TEST_F(FormatTestJS, ParameterNamingComment) {
+  verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
+}
+
 } // end namespace tooling
 } // end namespace clang


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
Right.MatchingParen->BlockKind != BK_Block))
 return !Style.Cpp11BracedListStyle;
   if (Left.is(TT_BlockComment))
-return !Left.TokenText.endswith("=*/");
+// No whitespace in x(/*foo=*/1), except for JavaScript.
+return Style.Language == FormatStyle::LK_JavaScript ||
+   !Left.TokenText.endswith("=*/");
   if (Right.is(tok::l_paren)) {
 if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
 (Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -2304,5 +2304,9 @@
  "};"));
 }
 
+TEST_F(FormatTestJS, ParameterNamingComment) {
+  verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
+}
+
 } // end namespace tooling
 } // end namespace clang
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52535: clang-format: [JS] space after parameter naming.

2018-09-26 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC343080: clang-format: [JS] space after parameter naming. 
(authored by mprobst, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D52535?vs=167073&id=167077#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D52535

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
Right.MatchingParen->BlockKind != BK_Block))
 return !Style.Cpp11BracedListStyle;
   if (Left.is(TT_BlockComment))
-return !Left.TokenText.endswith("=*/");
+// No whitespace in x(/*foo=*/1), except for JavaScript.
+return Style.Language == FormatStyle::LK_JavaScript ||
+   !Left.TokenText.endswith("=*/");
   if (Right.is(tok::l_paren)) {
 if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
 (Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2304,5 +2304,9 @@
  "};"));
 }
 
+TEST_F(FormatTestJS, ParameterNamingComment) {
+  verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
+}
+
 } // end namespace tooling
 } // end namespace clang


Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
Right.MatchingParen->BlockKind != BK_Block))
 return !Style.Cpp11BracedListStyle;
   if (Left.is(TT_BlockComment))
-return !Left.TokenText.endswith("=*/");
+// No whitespace in x(/*foo=*/1), except for JavaScript.
+return Style.Language == FormatStyle::LK_JavaScript ||
+   !Left.TokenText.endswith("=*/");
   if (Right.is(tok::l_paren)) {
 if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
 (Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2304,5 +2304,9 @@
  "};"));
 }
 
+TEST_F(FormatTestJS, ParameterNamingComment) {
+  verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
+}
+
 } // end namespace tooling
 } // end namespace clang
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52536: clang-format: [JS] conditional types.

2018-09-26 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.

This change adds some rudimentary support for conditional types.
Specifically it avoids breaking before `extends` and `infer` keywords,
which are subject to Automatic Semicolon Insertion, so breaking before
them creates incorrect syntax.

The actual formatting of the type expression is odd, but there is as of
yet no clear idea on how to format these.

See 
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types.


Repository:
  rC Clang

https://reviews.llvm.org/D52536

Files:
  lib/Format/FormatToken.h
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2308,5 +2308,12 @@
   verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
 }
 
+TEST_F(FormatTestJS, ConditionalTypes) {
+  verifyFormat("type UnionToIntersection =\n"
+   "(U extends any ? (k: U) => void :\n"
+   " never) extends((k: infer I) => void) ? I "
+   ": never;");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -3088,6 +3088,12 @@
   return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
 if (Right.is(Keywords.kw_as))
   return false; // must not break before as in 'x as type' casts
+if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) {
+  // extends and infer can appear as keywords in conditional types:
+  //   
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
+  // do not break before them, as the expressions are subject to ASI.
+  return false;
+}
 if (Left.is(Keywords.kw_as))
   return true;
 if (Left.is(TT_JsNonNullAssertion))
Index: lib/Format/FormatToken.h
===
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -680,6 +680,7 @@
 kw_function = &IdentTable.get("function");
 kw_get = &IdentTable.get("get");
 kw_import = &IdentTable.get("import");
+kw_infer = &IdentTable.get("infer");
 kw_is = &IdentTable.get("is");
 kw_let = &IdentTable.get("let");
 kw_module = &IdentTable.get("module");
@@ -751,6 +752,7 @@
   IdentifierInfo *kw_function;
   IdentifierInfo *kw_get;
   IdentifierInfo *kw_import;
+  IdentifierInfo *kw_infer;
   IdentifierInfo *kw_is;
   IdentifierInfo *kw_let;
   IdentifierInfo *kw_module;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2308,5 +2308,12 @@
   verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
 }
 
+TEST_F(FormatTestJS, ConditionalTypes) {
+  verifyFormat("type UnionToIntersection =\n"
+   "(U extends any ? (k: U) => void :\n"
+   " never) extends((k: infer I) => void) ? I "
+   ": never;");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -3088,6 +3088,12 @@
   return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
 if (Right.is(Keywords.kw_as))
   return false; // must not break before as in 'x as type' casts
+if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) {
+  // extends and infer can appear as keywords in conditional types:
+  //   https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
+  // do not break before them, as the expressions are subject to ASI.
+  return false;
+}
 if (Left.is(Keywords.kw_as))
   return true;
 if (Left.is(TT_JsNonNullAssertion))
Index: lib/Format/FormatToken.h
===
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -680,6 +680,7 @@
 kw_function = &IdentTable.get("function");
 kw_get = &IdentTable.get("get");
 kw_import = &IdentTable.get("import");
+kw_infer = &IdentTable.get("infer");
 kw_is = &IdentTable.get("is");
 kw_let = &IdentTable.get("let");
 kw_module = &IdentTable.get("module");
@@ -751,6 +752,7 @@
   IdentifierInfo *kw_function;
   IdentifierInfo *kw_get;
   IdentifierInfo *kw_import;
+  IdentifierInfo *kw_infer;
   IdentifierInfo *kw_is;
   IdentifierInfo *kw_let;
   IdentifierInfo *kw_module;
___
cfe-commits mailing list
cfe-commits@lists.l

[PATCH] D52536: clang-format: [JS] conditional types.

2018-09-26 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 167239.
mprobst added a comment.

- comment in test


Repository:
  rC Clang

https://reviews.llvm.org/D52536

Files:
  lib/Format/FormatToken.h
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2308,5 +2308,14 @@
   verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
 }
 
+TEST_F(FormatTestJS, ConditionalTypes) {
+  // Formatting below is not necessarily intentional, this just ensures that
+  // clang-format does not break the code.
+  verifyFormat( // wrap
+  "type UnionToIntersection =\n"
+  "(U extends any ? (k: U) => void :\n"
+  " never) extends((k: infer I) => void) ? I : 
never;");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -3088,6 +3088,12 @@
   return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
 if (Right.is(Keywords.kw_as))
   return false; // must not break before as in 'x as type' casts
+if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) {
+  // extends and infer can appear as keywords in conditional types:
+  //   
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
+  // do not break before them, as the expressions are subject to ASI.
+  return false;
+}
 if (Left.is(Keywords.kw_as))
   return true;
 if (Left.is(TT_JsNonNullAssertion))
Index: lib/Format/FormatToken.h
===
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -680,6 +680,7 @@
 kw_function = &IdentTable.get("function");
 kw_get = &IdentTable.get("get");
 kw_import = &IdentTable.get("import");
+kw_infer = &IdentTable.get("infer");
 kw_is = &IdentTable.get("is");
 kw_let = &IdentTable.get("let");
 kw_module = &IdentTable.get("module");
@@ -751,6 +752,7 @@
   IdentifierInfo *kw_function;
   IdentifierInfo *kw_get;
   IdentifierInfo *kw_import;
+  IdentifierInfo *kw_infer;
   IdentifierInfo *kw_is;
   IdentifierInfo *kw_let;
   IdentifierInfo *kw_module;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2308,5 +2308,14 @@
   verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
 }
 
+TEST_F(FormatTestJS, ConditionalTypes) {
+  // Formatting below is not necessarily intentional, this just ensures that
+  // clang-format does not break the code.
+  verifyFormat( // wrap
+  "type UnionToIntersection =\n"
+  "(U extends any ? (k: U) => void :\n"
+  " never) extends((k: infer I) => void) ? I : never;");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -3088,6 +3088,12 @@
   return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
 if (Right.is(Keywords.kw_as))
   return false; // must not break before as in 'x as type' casts
+if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) {
+  // extends and infer can appear as keywords in conditional types:
+  //   https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
+  // do not break before them, as the expressions are subject to ASI.
+  return false;
+}
 if (Left.is(Keywords.kw_as))
   return true;
 if (Left.is(TT_JsNonNullAssertion))
Index: lib/Format/FormatToken.h
===
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -680,6 +680,7 @@
 kw_function = &IdentTable.get("function");
 kw_get = &IdentTable.get("get");
 kw_import = &IdentTable.get("import");
+kw_infer = &IdentTable.get("infer");
 kw_is = &IdentTable.get("is");
 kw_let = &IdentTable.get("let");
 kw_module = &IdentTable.get("module");
@@ -751,6 +752,7 @@
   IdentifierInfo *kw_function;
   IdentifierInfo *kw_get;
   IdentifierInfo *kw_import;
+  IdentifierInfo *kw_infer;
   IdentifierInfo *kw_is;
   IdentifierInfo *kw_let;
   IdentifierInfo *kw_module;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52536: clang-format: [JS] conditional types.

2018-09-26 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL343179: clang-format: [JS] conditional types. (authored by 
mprobst, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D52536

Files:
  cfe/trunk/lib/Format/FormatToken.h
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -3088,6 +3088,12 @@
   return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
 if (Right.is(Keywords.kw_as))
   return false; // must not break before as in 'x as type' casts
+if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) {
+  // extends and infer can appear as keywords in conditional types:
+  //   
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
+  // do not break before them, as the expressions are subject to ASI.
+  return false;
+}
 if (Left.is(Keywords.kw_as))
   return true;
 if (Left.is(TT_JsNonNullAssertion))
Index: cfe/trunk/lib/Format/FormatToken.h
===
--- cfe/trunk/lib/Format/FormatToken.h
+++ cfe/trunk/lib/Format/FormatToken.h
@@ -680,6 +680,7 @@
 kw_function = &IdentTable.get("function");
 kw_get = &IdentTable.get("get");
 kw_import = &IdentTable.get("import");
+kw_infer = &IdentTable.get("infer");
 kw_is = &IdentTable.get("is");
 kw_let = &IdentTable.get("let");
 kw_module = &IdentTable.get("module");
@@ -751,6 +752,7 @@
   IdentifierInfo *kw_function;
   IdentifierInfo *kw_get;
   IdentifierInfo *kw_import;
+  IdentifierInfo *kw_infer;
   IdentifierInfo *kw_is;
   IdentifierInfo *kw_let;
   IdentifierInfo *kw_module;
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -2308,5 +2308,14 @@
   verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
 }
 
+TEST_F(FormatTestJS, ConditionalTypes) {
+  // Formatting below is not necessarily intentional, this just ensures that
+  // clang-format does not break the code.
+  verifyFormat( // wrap
+  "type UnionToIntersection =\n"
+  "(U extends any ? (k: U) => void :\n"
+  " never) extends((k: infer I) => void) ? I : 
never;");
+}
+
 } // end namespace tooling
 } // end namespace clang


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -3088,6 +3088,12 @@
   return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
 if (Right.is(Keywords.kw_as))
   return false; // must not break before as in 'x as type' casts
+if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) {
+  // extends and infer can appear as keywords in conditional types:
+  //   https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
+  // do not break before them, as the expressions are subject to ASI.
+  return false;
+}
 if (Left.is(Keywords.kw_as))
   return true;
 if (Left.is(TT_JsNonNullAssertion))
Index: cfe/trunk/lib/Format/FormatToken.h
===
--- cfe/trunk/lib/Format/FormatToken.h
+++ cfe/trunk/lib/Format/FormatToken.h
@@ -680,6 +680,7 @@
 kw_function = &IdentTable.get("function");
 kw_get = &IdentTable.get("get");
 kw_import = &IdentTable.get("import");
+kw_infer = &IdentTable.get("infer");
 kw_is = &IdentTable.get("is");
 kw_let = &IdentTable.get("let");
 kw_module = &IdentTable.get("module");
@@ -751,6 +752,7 @@
   IdentifierInfo *kw_function;
   IdentifierInfo *kw_get;
   IdentifierInfo *kw_import;
+  IdentifierInfo *kw_infer;
   IdentifierInfo *kw_is;
   IdentifierInfo *kw_let;
   IdentifierInfo *kw_module;
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -2308,5 +2308,14 @@
   verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
 }
 
+TEST_F(FormatTestJS, ConditionalTypes) {
+  // Formatting below is not necessarily intentional, this just ensures that
+  // clang-format does not break the code.
+  verifyFormat( // wrap
+  "type UnionToIntersection =\n"
+  "(U extends any ? (k: U) => void :\n"
+  " never) extends((k: infer I) => void) ? I : never;");
+}
+
 } // end namespace tooling
 } // end nam

[PATCH] D37142: clang-format: [JS] simplify template string wrapping.

2017-08-25 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

Previously, clang-format would try to wrap template string substitutions
by indenting relative to the openening `${`. This helped with
indenting structured strings, such as strings containing HTML, as the
substitutions would be aligned according to the structure of the string.

However it turns out that the overwhelming majority of template string +
substitution usages are for substitutions into non-structured strings,
e.g. URLs or just plain messages. For these situations, clang-format
would often produce very ugly indents, in particular for strings
containing no line breaks:

  return `${file}(${
  row
},${
col
  }): `;

This change makes clang-format indent template string substitutions as
if they were string concatenation operations. It wraps +4 on overlong
lines and keeps all operands on the same line:

  return `${file}(${
  row},${col}): `;

While this breaks some lexical continuity between the `${` and `row}`
here, the overall effects are still a huge improvement, and users can
still manually break the string using `+` if desired.


https://reviews.llvm.org/D37142

Files:
  lib/Format/ContinuationIndenter.cpp
  unittests/Format/FormatTestJS.cpp

Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1793,43 +1793,39 @@
   verifyFormat("var x = someFunction(`${})`)  //\n"
".oon();");
   verifyFormat("var x = someFunction(`${}${\n"
-   "   a(  //\n"
-   "   a)\n"
-   " })`);");
+   "a(  //\n"
+   "a)})`);");
 }
 
 TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
   verifyFormat("var f = `aa: ${\n"
-   "   a +  //\n"
-   "   \n"
-   " }`;",
+   "a +  //\n"
+   "}`;",
"var f = `aa: ${a +  //\n"
"   }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "a +  //\n"
-   "\n"
-   "  }`;",
+   "a +  //\n"
+   "}`;",
"var f  =  `\n"
"  aa: ${   a  +  //\n"
" }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "someFunction(\n"
-   "a +  //\n"
-   ")\n"
-   "  }`;",
+   "someFunction(\n"
+   "a +  //\n"
+   ")}`;",
"var f  =  `\n"
"  aa: ${someFunction (\n"
"a  +   //\n"
")}`;");
 
   // It might be preferable to wrap before "someFunction".
   verifyFormat("var f = `\n"
"  aa: ${someFunction({\n"
-   "  : a,\n"
-   "  : b,\n"
-   "})}`;",
+   "  : a,\n"
+   "  : b,\n"
+   "})}`;",
"var f  =  `\n"
"  aa: ${someFunction ({\n"
"  :  a,\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -661,9 +661,7 @@
   // before the corresponding } or ].
   if (PreviousNonComment &&
   (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
-   opensProtoMessageField(*PreviousNonComment, Style) ||
-   (PreviousNonComment->is(TT_TemplateString) &&
-PreviousNonComment->opensScope(
+   opensProtoMessageField(*PreviousNonComment, Style)))
 State.Stack.back().BreakBeforeClosingBrace = true;
 
   if (State.Stack.back().AvoidBinPacking) {
@@ -925,11 +923,6 @@
 
   moveStatePastFakeLParens(State, Newline);
   moveStatePastScopeClos

[PATCH] D37142: clang-format: [JS] simplify template string wrapping.

2017-08-28 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 112858.
mprobst added a comment.

- clang-format: [JS] wrap calls w/ literals in template strings.


https://reviews.llvm.org/D37142

Files:
  lib/Format/ContinuationIndenter.cpp
  unittests/Format/FormatTestJS.cpp

Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1793,43 +1793,38 @@
   verifyFormat("var x = someFunction(`${})`)  //\n"
".oon();");
   verifyFormat("var x = someFunction(`${}${\n"
-   "   a(  //\n"
-   "   a)\n"
-   " })`);");
+   "a(  //\n"
+   "a)})`);");
 }
 
 TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
   verifyFormat("var f = `aa: ${\n"
-   "   a +  //\n"
-   "   \n"
-   " }`;",
+   "a +  //\n"
+   "}`;",
"var f = `aa: ${a +  //\n"
"   }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "a +  //\n"
-   "\n"
-   "  }`;",
+   "a +  //\n"
+   "}`;",
"var f  =  `\n"
"  aa: ${   a  +  //\n"
" }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "someFunction(\n"
-   "a +  //\n"
-   ")\n"
-   "  }`;",
+   "someFunction(\n"
+   "a +  //\n"
+   ")}`;",
"var f  =  `\n"
"  aa: ${someFunction (\n"
"a  +   //\n"
")}`;");
-
-  // It might be preferable to wrap before "someFunction".
   verifyFormat("var f = `\n"
-   "  aa: ${someFunction({\n"
-   "  : a,\n"
-   "  : b,\n"
-   "})}`;",
+   "  aa: ${\n"
+   "someFunction({\n"
+   "  : a,\n"
+   "  : b,\n"
+   "})}`;",
"var f  =  `\n"
"  aa: ${someFunction ({\n"
"  :  a,\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -661,9 +661,7 @@
   // before the corresponding } or ].
   if (PreviousNonComment &&
   (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
-   opensProtoMessageField(*PreviousNonComment, Style) ||
-   (PreviousNonComment->is(TT_TemplateString) &&
-PreviousNonComment->opensScope(
+   opensProtoMessageField(*PreviousNonComment, Style)))
 State.Stack.back().BreakBeforeClosingBrace = true;
 
   if (State.Stack.back().AvoidBinPacking) {
@@ -925,11 +923,6 @@
 
   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("${");
   bool CanBreakProtrudingToken = !State.Stack.back().NoLineBreak &&
  !State.Stack.back().NoLineBreakInOperand;
   moveStatePastScopeOpener(State, Newline);
@@ -1101,18 +1094,6 @@
   LastSpace = std::max(LastSpace, State.Stack.back().Indent);
 }
 
-// JavaScript template strings are special as we always want to indent
-// nested expressions relative to the ${}. Otherwise, this can create quite
-// a mess.
-if (Current.is(TT_TemplateString)) {
-  unsigned Column = Current.IsMultiline
-? Current.LastLineColumnWidth
-: State.Column + Current.ColumnWidth;
-  NewIndent = Column;
-  LastSpace = Column;
-  NestedBlockIndent = Column;
-}
-
 bool EndsInComma =
 Current.MatchingParen &&
 Current.MatchingParen->getPreviousNonComment() &&
@

[PATCH] D37142: clang-format: [JS] simplify template string wrapping.

2017-08-28 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: lib/Format/ContinuationIndenter.cpp:1139
+
+  // On lines containing template strings, propagate NoLineBreak even for dict
+  // and array literals. This is to force wrapping an initial function call if

djasper wrote:
> This is not the right way to implement this:
> 
> - This is a static computation that we could do ahead of time. Doing it 
> inside the combinatorial exploration of solutions is a waste.
> - You are doing this always, even in code that doesn't have template strings 
> or isn't even JavaScript.
> - This can lead to unexpected behavior if the template string is in a 
> completely unrelated part of the statement. E.g.
> 
> 
>   someFunction(`test`, { ... });
> 
> will be formatted differently from
> 
>   someFunction('test', { ... });
Ack. Do you have suggestions?

I could introduce a `bool  ParenState::NoLineBreakMustPropagate;` that controls 
this behaviour.


https://reviews.llvm.org/D37142



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D37142: clang-format: [JS] simplify template string wrapping.

2017-08-28 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: lib/Format/ContinuationIndenter.cpp:1139
+
+  // On lines containing template strings, propagate NoLineBreak even for dict
+  // and array literals. This is to force wrapping an initial function call if

djasper wrote:
> mprobst wrote:
> > djasper wrote:
> > > This is not the right way to implement this:
> > > 
> > > - This is a static computation that we could do ahead of time. Doing it 
> > > inside the combinatorial exploration of solutions is a waste.
> > > - You are doing this always, even in code that doesn't have template 
> > > strings or isn't even JavaScript.
> > > - This can lead to unexpected behavior if the template string is in a 
> > > completely unrelated part of the statement. E.g.
> > > 
> > > 
> > >   someFunction(`test`, { ... });
> > > 
> > > will be formatted differently from
> > > 
> > >   someFunction('test', { ... });
> > Ack. Do you have suggestions?
> > 
> > I could introduce a `bool  ParenState::NoLineBreakMustPropagate;` that 
> > controls this behaviour.
> That, too, would create a significant memory and runtime overhead to everyone 
> just to fix this rather minor formatting detail.
> If we were to set MatchingParen correctly to match up "${" to "}", we could 
> measure the respective length and at a very early state (mustBreak()) decide 
> that we need a line break between "${" and the corresponding "}". Now setting 
> that correctly might be hard. Maybe it is ok, to linearly scan in that case 
> as we would only do that if we actually find a template string ending in "${" 
> and the distance to the "}" is usually short.
I cannot decide whether I must break in `mustBreak` - I need to just force 
wrapping after `${` if I need to wrap somewhere below, but if the code fits on 
the line, I don't want to wrap. So when I'm visiting `${` I cannot decide that, 
and when I'm at the object literal expression, the decision for `${` has 
already been made - right? Or am I missing something?


https://reviews.llvm.org/D37142



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D37142: clang-format: [JS] simplify template string wrapping.

2017-08-29 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 113036.
mprobst added a comment.

- drop function name wrapping hack


https://reviews.llvm.org/D37142

Files:
  lib/Format/ContinuationIndenter.cpp
  unittests/Format/FormatTestJS.cpp

Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1793,43 +1793,39 @@
   verifyFormat("var x = someFunction(`${})`)  //\n"
".oon();");
   verifyFormat("var x = someFunction(`${}${\n"
-   "   a(  //\n"
-   "   a)\n"
-   " })`);");
+   "a(  //\n"
+   "a)})`);");
 }
 
 TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
   verifyFormat("var f = `aa: ${\n"
-   "   a +  //\n"
-   "   \n"
-   " }`;",
+   "a +  //\n"
+   "}`;",
"var f = `aa: ${a +  //\n"
"   }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "a +  //\n"
-   "\n"
-   "  }`;",
+   "a +  //\n"
+   "}`;",
"var f  =  `\n"
"  aa: ${   a  +  //\n"
" }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "someFunction(\n"
-   "a +  //\n"
-   ")\n"
-   "  }`;",
+   "someFunction(\n"
+   "a +  //\n"
+   ")}`;",
"var f  =  `\n"
"  aa: ${someFunction (\n"
"a  +   //\n"
")}`;");
 
   // It might be preferable to wrap before "someFunction".
   verifyFormat("var f = `\n"
"  aa: ${someFunction({\n"
-   "  : a,\n"
-   "  : b,\n"
-   "})}`;",
+   "  : a,\n"
+   "  : b,\n"
+   "})}`;",
"var f  =  `\n"
"  aa: ${someFunction ({\n"
"  :  a,\n"
Index: lib/Format/ContinuationIndenter.cpp
===
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -661,9 +661,7 @@
   // before the corresponding } or ].
   if (PreviousNonComment &&
   (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
-   opensProtoMessageField(*PreviousNonComment, Style) ||
-   (PreviousNonComment->is(TT_TemplateString) &&
-PreviousNonComment->opensScope(
+   opensProtoMessageField(*PreviousNonComment, Style)))
 State.Stack.back().BreakBeforeClosingBrace = true;
 
   if (State.Stack.back().AvoidBinPacking) {
@@ -925,11 +923,6 @@
 
   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("${");
   bool CanBreakProtrudingToken = !State.Stack.back().NoLineBreak &&
  !State.Stack.back().NoLineBreakInOperand;
   moveStatePastScopeOpener(State, Newline);
@@ -1101,18 +1094,6 @@
   LastSpace = std::max(LastSpace, State.Stack.back().Indent);
 }
 
-// JavaScript template strings are special as we always want to indent
-// nested expressions relative to the ${}. Otherwise, this can create quite
-// a mess.
-if (Current.is(TT_TemplateString)) {
-  unsigned Column = Current.IsMultiline
-? Current.LastLineColumnWidth
-: State.Column + Current.ColumnWidth;
-  NewIndent = Column;
-  LastSpace = Column;
-  NestedBlockIndent = Column;
-}
-
 bool EndsInComma =
 Current.MatchingParen &&
 Current.MatchingParen->getPreviousNonComment() &&
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-b

[PATCH] D37142: clang-format: [JS] simplify template string wrapping.

2017-08-29 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: lib/Format/ContinuationIndenter.cpp:1139
+
+  // On lines containing template strings, propagate NoLineBreak even for dict
+  // and array literals. This is to force wrapping an initial function call if

mprobst wrote:
> djasper wrote:
> > mprobst wrote:
> > > djasper wrote:
> > > > This is not the right way to implement this:
> > > > 
> > > > - This is a static computation that we could do ahead of time. Doing it 
> > > > inside the combinatorial exploration of solutions is a waste.
> > > > - You are doing this always, even in code that doesn't have template 
> > > > strings or isn't even JavaScript.
> > > > - This can lead to unexpected behavior if the template string is in a 
> > > > completely unrelated part of the statement. E.g.
> > > > 
> > > > 
> > > >   someFunction(`test`, { ... });
> > > > 
> > > > will be formatted differently from
> > > > 
> > > >   someFunction('test', { ... });
> > > Ack. Do you have suggestions?
> > > 
> > > I could introduce a `bool  ParenState::NoLineBreakMustPropagate;` that 
> > > controls this behaviour.
> > That, too, would create a significant memory and runtime overhead to 
> > everyone just to fix this rather minor formatting detail.
> > If we were to set MatchingParen correctly to match up "${" to "}", we could 
> > measure the respective length and at a very early state (mustBreak()) 
> > decide that we need a line break between "${" and the corresponding "}". 
> > Now setting that correctly might be hard. Maybe it is ok, to linearly scan 
> > in that case as we would only do that if we actually find a template string 
> > ending in "${" and the distance to the "}" is usually short.
> I cannot decide whether I must break in `mustBreak` - I need to just force 
> wrapping after `${` if I need to wrap somewhere below, but if the code fits 
> on the line, I don't want to wrap. So when I'm visiting `${` I cannot decide 
> that, and when I'm at the object literal expression, the decision for `${` 
> has already been made - right? Or am I missing something?
I've dropped the function wrapping fix and will land like this, apparently 
we'll need to think about this a bit more.


https://reviews.llvm.org/D37142



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D37142: clang-format: [JS] simplify template string wrapping.

2017-08-29 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL311988: clang-format: [JS] simplify template string 
wrapping. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D37142

Files:
  cfe/trunk/lib/Format/ContinuationIndenter.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp

Index: cfe/trunk/lib/Format/ContinuationIndenter.cpp
===
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp
@@ -661,9 +661,7 @@
   // before the corresponding } or ].
   if (PreviousNonComment &&
   (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
-   opensProtoMessageField(*PreviousNonComment, Style) ||
-   (PreviousNonComment->is(TT_TemplateString) &&
-PreviousNonComment->opensScope(
+   opensProtoMessageField(*PreviousNonComment, Style)))
 State.Stack.back().BreakBeforeClosingBrace = true;
 
   if (State.Stack.back().AvoidBinPacking) {
@@ -925,11 +923,6 @@
 
   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("${");
   bool CanBreakProtrudingToken = !State.Stack.back().NoLineBreak &&
  !State.Stack.back().NoLineBreakInOperand;
   moveStatePastScopeOpener(State, Newline);
@@ -1101,18 +1094,6 @@
   LastSpace = std::max(LastSpace, State.Stack.back().Indent);
 }
 
-// JavaScript template strings are special as we always want to indent
-// nested expressions relative to the ${}. Otherwise, this can create quite
-// a mess.
-if (Current.is(TT_TemplateString)) {
-  unsigned Column = Current.IsMultiline
-? Current.LastLineColumnWidth
-: State.Column + Current.ColumnWidth;
-  NewIndent = Column;
-  LastSpace = Column;
-  NestedBlockIndent = Column;
-}
-
 bool EndsInComma =
 Current.MatchingParen &&
 Current.MatchingParen->getPreviousNonComment() &&
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1793,43 +1793,39 @@
   verifyFormat("var x = someFunction(`${})`)  //\n"
".oon();");
   verifyFormat("var x = someFunction(`${}${\n"
-   "   a(  //\n"
-   "   a)\n"
-   " })`);");
+   "a(  //\n"
+   "a)})`);");
 }
 
 TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
   verifyFormat("var f = `aa: ${\n"
-   "   a +  //\n"
-   "   \n"
-   " }`;",
+   "a +  //\n"
+   "}`;",
"var f = `aa: ${a +  //\n"
"   }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "a +  //\n"
-   "\n"
-   "  }`;",
+   "a +  //\n"
+   "}`;",
"var f  =  `\n"
"  aa: ${   a  +  //\n"
" }`;");
   verifyFormat("var f = `\n"
"  aa: ${\n"
-   "someFunction(\n"
-   "a +  //\n"
-   ")\n"
-   "  }`;",
+   "someFunction(\n"
+   "a +  //\n"
+   ")}`;",
"var f  =  `\n"
"  aa: ${someFunction (\n"
"a  +   //\n"
")}`;");
 
   // It might be preferable to wrap before "someFunction".
   verifyFormat("var f = `\n"
"  aa: ${someFunction({\n"
-   "  : a,\n"
-   "  : b,\n"
-   "})}`;",
+   "  : a,\n"
+   "  : b,\n"
+   "})}`;",
"var f  =  `\n"
"  aa: ${someFunction ({\n"
 

[PATCH] D56385: clang-format: [JS] support goog.requireType.

2019-01-07 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.

It's a new primitive for importing symbols, and should be treated like
the (previously handled) `goog.require` and `goog.forwardDeclare`.


Repository:
  rC Clang

https://reviews.llvm.org/D56385

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -600,6 +600,8 @@
getGoogleJSStyleWithColumns(40));
   verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
+  verifyFormat("const X = goog.requireType('this.is.really.absurdly.long');",
+   getGoogleJSStyleWithColumns(40));
   verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
 
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -1123,6 +1123,7 @@
(Tok.Next->Next->TokenText == "module" ||
 Tok.Next->Next->TokenText == "provide" ||
 Tok.Next->Next->TokenText == "require" ||
+Tok.Next->Next->TokenText == "requireType" ||
 Tok.Next->Next->TokenText == "forwardDeclare") &&
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
   }


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -600,6 +600,8 @@
getGoogleJSStyleWithColumns(40));
   verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
+  verifyFormat("const X = goog.requireType('this.is.really.absurdly.long');",
+   getGoogleJSStyleWithColumns(40));
   verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
 
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -1123,6 +1123,7 @@
(Tok.Next->Next->TokenText == "module" ||
 Tok.Next->Next->TokenText == "provide" ||
 Tok.Next->Next->TokenText == "require" ||
+Tok.Next->Next->TokenText == "requireType" ||
 Tok.Next->Next->TokenText == "forwardDeclare") &&
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
   }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D56385: clang-format: [JS] support goog.requireType.

2019-01-07 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL350516: clang-format: [JS] support goog.requireType. 
(authored by mprobst, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56385/new/

https://reviews.llvm.org/D56385

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -1123,6 +1123,7 @@
(Tok.Next->Next->TokenText == "module" ||
 Tok.Next->Next->TokenText == "provide" ||
 Tok.Next->Next->TokenText == "require" ||
+Tok.Next->Next->TokenText == "requireType" ||
 Tok.Next->Next->TokenText == "forwardDeclare") &&
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
   }
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -600,6 +600,8 @@
getGoogleJSStyleWithColumns(40));
   verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
+  verifyFormat("const X = goog.requireType('this.is.really.absurdly.long');",
+   getGoogleJSStyleWithColumns(40));
   verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
 


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -1123,6 +1123,7 @@
(Tok.Next->Next->TokenText == "module" ||
 Tok.Next->Next->TokenText == "provide" ||
 Tok.Next->Next->TokenText == "require" ||
+Tok.Next->Next->TokenText == "requireType" ||
 Tok.Next->Next->TokenText == "forwardDeclare") &&
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
   }
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -600,6 +600,8 @@
getGoogleJSStyleWithColumns(40));
   verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
+  verifyFormat("const X = goog.requireType('this.is.really.absurdly.long');",
+   getGoogleJSStyleWithColumns(40));
   verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');",
getGoogleJSStyleWithColumns(40));
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst marked 2 inline comments as done.
mprobst added inline comments.



Comment at: clang/lib/Format/FormatToken.h:913
   bool IsJavaScriptIdentifier(const FormatToken &Tok) const {
-return Tok.is(tok::identifier) &&
-   JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
-   JsExtraKeywords.end();
+switch (Tok.Tok.getKind()) {
+case tok::kw_break:

krasimir wrote:
> nit: may be worth adding a comment linking to:
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords
Done, though I used the TS list of keywords (as it's a superset of the JS 
keywords).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
mprobst marked an inline comment as done.
Closed by commit rG146d685cd657: clang-format: [JS] detect C++ keywords. 
(authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D77311?vs=254741&id=254763#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp

Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -386,13 +386,6 @@
"return (x);\n");
 }
 
-TEST_F(FormatTestJS, CppKeywords) {
-  // Make sure we don't mess stuff up because of C++ keywords.
-  verifyFormat("return operator && (aa);");
-  // .. or QT ones.
-  verifyFormat("slots: Slot[];");
-}
-
 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
   verifyFormat("var [a, b, c] = [1, 2, 3];");
   verifyFormat("const [a, b, c] = [1, 2, 3];");
@@ -2366,6 +2359,61 @@
   verifyFormat("return !!x;\n");
 }
 
+TEST_F(FormatTestJS, CppKeywords) {
+  // Make sure we don't mess stuff up because of C++ keywords.
+  verifyFormat("return operator && (aa);");
+  // .. or QT ones.
+  verifyFormat("const slots: Slot[];");
+  // use the "!" assertion operator to validate that clang-format understands
+  // these C++ keywords aren't keywords in JS/TS.
+  verifyFormat("auto!;");
+  verifyFormat("char!;");
+  verifyFormat("concept!;");
+  verifyFormat("double!;");
+  verifyFormat("extern!;");
+  verifyFormat("float!;");
+  verifyFormat("inline!;");
+  verifyFormat("int!;");
+  verifyFormat("long!;");
+  verifyFormat("register!;");
+  verifyFormat("restrict!;");
+  verifyFormat("sizeof!;");
+  verifyFormat("struct!;");
+  verifyFormat("typedef!;");
+  verifyFormat("union!;");
+  verifyFormat("unsigned!;");
+  verifyFormat("volatile!;");
+  verifyFormat("_Alignas!;");
+  verifyFormat("_Alignof!;");
+  verifyFormat("_Atomic!;");
+  verifyFormat("_Bool!;");
+  verifyFormat("_Complex!;");
+  verifyFormat("_Generic!;");
+  verifyFormat("_Imaginary!;");
+  verifyFormat("_Noreturn!;");
+  verifyFormat("_Static_assert!;");
+  verifyFormat("_Thread_local!;");
+  verifyFormat("__func__!;");
+  verifyFormat("__objc_yes!;");
+  verifyFormat("__objc_no!;");
+  verifyFormat("asm!;");
+  verifyFormat("bool!;");
+  verifyFormat("const_cast!;");
+  verifyFormat("dynamic_cast!;");
+  verifyFormat("explicit!;");
+  verifyFormat("friend!;");
+  verifyFormat("mutable!;");
+  verifyFormat("operator!;");
+  verifyFormat("reinterpret_cast!;");
+  verifyFormat("static_cast!;");
+  verifyFormat("template!;");
+  verifyFormat("typename!;");
+  verifyFormat("typeid!;");
+  verifyFormat("using!;");
+  verifyFormat("virtual!;");
+  verifyFormat("wchar_t!;");
+}
+
 TEST_F(FormatTestJS, NullPropagatingOperator) {
   verifyFormat("let x = foo?.bar?.baz();\n");
   verifyFormat("let x = foo?.(foo);\n");
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,9 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
-(Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
-   tok::r_paren, tok::r_square,
-   tok::r_brace) ||
+(Keywords.IsJavaScriptIdentifier(*Current.Previous) ||
+ Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren,
+   tok::r_square, tok::r_brace) ||
  Current.Previous->Tok.isLiteral())) {
   Current.Type = TT_JsNonNullAssertion;
   return;
@@ -3070,10 +3070,8 @@
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return false;
 // In tagged template literals ("html`bar baz`"), there is no space between
-// the tag identifier and the template string. getIdentifierInfo makes sure
-// that the identifier is not a pseudo keyword like `yield`, either.
-if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
-Right.is(TT_TemplateString))
+// the tag identifier and the template string.
+if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString))
   return false;
 if (Right.is(tok::star) &&
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -910,9 +910,64 @@
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c fa

[PATCH] D77548: clang-format: [JS] handle pseudo-keywords.

2020-04-06 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The previous change in https://reviews.llvm.org/D77311 attempted to
detect more C++ keywords. However it also precisely detected all
JavaScript keywords. That's generally correct, but many JavaScripy
keywords, e.g. `get`, are so-called pseudo-keywords. They can be used in
positions where a keyword would never be legal, e.g. in a dotted
expression:

  x.type;  // type is a pseudo-keyword, but can be used here.
  x.get;   // same for get etc.

This change introduces an additional parameter to
`IsJavaScriptIdentifier`, allowing clients to toggle whether they want
to allow `IdentifierName` tokens, i.e. pseudo-keywords.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77548

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2412,6 +2412,11 @@
   verifyFormat("using!;");
   verifyFormat("virtual!;");
   verifyFormat("wchar_t!;");
+
+  // Positive tests:
+  verifyFormat("x.type!;");
+  verifyFormat("x.get!;");
+  verifyFormat("x.set!;");
 }
 
 TEST_F(FormatTestJS, NullPropagatingOperator) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,11 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
-(Keywords.IsJavaScriptIdentifier(*Current.Previous) ||
- Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren,
-   tok::r_square, tok::r_brace) ||
+(Keywords.IsJavaScriptIdentifier(
+ *Current.Previous, /* AcceptIdentifierName= */ true) ||
+ Current.Previous->isOneOf(
+ tok::kw_namespace, tok::r_paren, tok::r_square, tok::r_brace,
+ Keywords.kw_type, Keywords.kw_get, Keywords.kw_set) ||
  Current.Previous->Tok.isLiteral())) {
   Current.Type = TT_JsNonNullAssertion;
   return;
@@ -3071,7 +3073,9 @@
   return false;
 // In tagged template literals ("html`bar baz`"), there is no space between
 // the tag identifier and the template string.
-if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString))
+if (Keywords.IsJavaScriptIdentifier(Left,
+/* AcceptIdentifierName= */ false) &&
+Right.is(TT_TemplateString))
   return false;
 if (Right.is(tok::star) &&
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -909,7 +909,11 @@
 
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c false if it is a keyword or a pseudo keyword.
-  bool IsJavaScriptIdentifier(const FormatToken &Tok) const {
+  /// If \c AcceptIdentifierName is true, returns true not only for keywords,
+  // but also for IdentifierName tokens (aka pseudo-keywords), such as
+  // ``yield``.
+  bool IsJavaScriptIdentifier(const FormatToken &Tok,
+  bool AcceptIdentifierName = true) const {
 // Based on the list of JavaScript & TypeScript keywords here:
 // 
https://github.com/microsoft/TypeScript/blob/master/src/compiler/scanner.ts#L74
 switch (Tok.Tok.getKind()) {
@@ -946,11 +950,14 @@
 case tok::kw_while:
   // These are JS keywords that are lexed by LLVM/clang as keywords.
   return false;
-case tok::identifier:
+case tok::identifier:  {
   // For identifiers, make sure they are true identifiers, excluding the
   // JavaScript pseudo-keywords (not lexed by LLVM/clang as keywords).
-  return JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
- JsExtraKeywords.end();
+bool IsPseudoKeyword =
+  JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) !=
+  JsExtraKeywords.end();
+  return AcceptIdentifierName || !IsPseudoKeyword;
+}
 default:
   // Other keywords are handled in the switch below, to avoid problems due
   // to duplicate case labels when using the #include trick.


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2412,6 +2412,11 @@
   verifyFormat("using!;");
   verifyFormat("virtual!;");
   verifyFormat("wchar_t!;");
+
+  // Positive tests:
+  verif

[PATCH] D77548: clang-format: [JS] handle pseudo-keywords.

2020-04-06 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG92201505cdec: clang-format: [JS] handle pseudo-keywords. 
(authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D77548?vs=255314&id=255357#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77548/new/

https://reviews.llvm.org/D77548

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2412,6 +2412,11 @@
   verifyFormat("using!;");
   verifyFormat("virtual!;");
   verifyFormat("wchar_t!;");
+
+  // Positive tests:
+  verifyFormat("x.type!;");
+  verifyFormat("x.get!;");
+  verifyFormat("x.set!;");
 }
 
 TEST_F(FormatTestJS, NullPropagatingOperator) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,11 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
-(Keywords.IsJavaScriptIdentifier(*Current.Previous) ||
- Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren,
-   tok::r_square, tok::r_brace) ||
+(Keywords.IsJavaScriptIdentifier(
+ *Current.Previous, /* AcceptIdentifierName= */ true) ||
+ Current.Previous->isOneOf(
+ tok::kw_namespace, tok::r_paren, tok::r_square, tok::r_brace,
+ Keywords.kw_type, Keywords.kw_get, Keywords.kw_set) ||
  Current.Previous->Tok.isLiteral())) {
   Current.Type = TT_JsNonNullAssertion;
   return;
@@ -3071,7 +3073,9 @@
   return false;
 // In tagged template literals ("html`bar baz`"), there is no space between
 // the tag identifier and the template string.
-if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString))
+if (Keywords.IsJavaScriptIdentifier(Left,
+/* AcceptIdentifierName= */ false) &&
+Right.is(TT_TemplateString))
   return false;
 if (Right.is(tok::star) &&
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -909,7 +909,11 @@
 
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c false if it is a keyword or a pseudo keyword.
-  bool IsJavaScriptIdentifier(const FormatToken &Tok) const {
+  /// If \c AcceptIdentifierName is true, returns true not only for keywords,
+  // but also for IdentifierName tokens (aka pseudo-keywords), such as
+  // ``yield``.
+  bool IsJavaScriptIdentifier(const FormatToken &Tok,
+  bool AcceptIdentifierName = true) const {
 // Based on the list of JavaScript & TypeScript keywords here:
 // 
https://github.com/microsoft/TypeScript/blob/master/src/compiler/scanner.ts#L74
 switch (Tok.Tok.getKind()) {
@@ -946,11 +950,14 @@
 case tok::kw_while:
   // These are JS keywords that are lexed by LLVM/clang as keywords.
   return false;
-case tok::identifier:
+case tok::identifier: {
   // For identifiers, make sure they are true identifiers, excluding the
   // JavaScript pseudo-keywords (not lexed by LLVM/clang as keywords).
-  return JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
- JsExtraKeywords.end();
+  bool IsPseudoKeyword =
+  JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) !=
+  JsExtraKeywords.end();
+  return AcceptIdentifierName || !IsPseudoKeyword;
+}
 default:
   // Other keywords are handled in the switch below, to avoid problems due
   // to duplicate case labels when using the #include trick.


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2412,6 +2412,11 @@
   verifyFormat("using!;");
   verifyFormat("virtual!;");
   verifyFormat("wchar_t!;");
+
+  // Positive tests:
+  verifyFormat("x.type!;");
+  verifyFormat("x.get!;");
+  verifyFormat("x.set!;");
 }
 
 TEST_F(FormatTestJS, NullPropagatingOperator) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,11 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 

[PATCH] D40410: clang-format: [JS] disable ASI on decorators.

2017-11-24 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

Automatic Semicolon Insertion in clang-format tries to guess if a line
wrap should insert an implicit semicolong. The previous heuristic would
not trigger ASI if a token was immediately preceded by an `@` sign:

  function foo(@Bar  // <-- does not trigger due to preceding @
  baz) {}

However decorators can have arbitrary parameters:

  function foo(@Bar(param, param, param)  // <-- precending @ missed
  baz) {}

While it would be possible to precisely find the matching `@`, just
conversatively disabling ASI for the entire line is simpler, while also
not regressing ASI substatially.


https://reviews.llvm.org/D40410

Files:
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1192,6 +1192,8 @@
   "String");
   verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n"
   "  bar) {}");
+  verifyFormat("function f(@Foo(Param) bar) {}", "function f(@Foo(Param)\n"
+ "  bar) {}");
   verifyFormat("a = true\n"
"return 1",
"a = true\n"
@@ -1557,7 +1559,7 @@
"}");
 }
 
-TEST_F(FormatTestJS, MetadataAnnotations) {
+TEST_F(FormatTestJS, Decorators) {
   verifyFormat("@A\nclass C {\n}");
   verifyFormat("@A({arg: 'value'})\nclass C {\n}");
   verifyFormat("@A\n@B\nclass C {\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -18,6 +18,8 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 
+#include 
+
 #define DEBUG_TYPE "format-parser"
 
 namespace clang {
@@ -891,11 +893,14 @@
   bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
   bool PreviousStartsTemplateExpr =
   Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
-  if (PreviousMustBeValue && Line && Line->Tokens.size() > 1) {
-// If the token before the previous one is an '@', the previous token is an
-// annotation and can precede another identifier/value.
-const FormatToken *PrePrevious = std::prev(Line->Tokens.end(), 2)->Tok;
-if (PrePrevious->is(tok::at))
+  if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
+// If the line contains an '@' sign, the previous token might be an
+// annotation, which can precede another identifier/value.
+bool HasAt = std::find_if(Line->Tokens.begin(), Line->Tokens.end(),
+  [](UnwrappedLineNode &LineNode) {
+return LineNode.Tok->is(tok::at);
+  }) != Line->Tokens.end();
+if (HasAt)
   return;
   }
   if (Next->is(tok::exclaim) && PreviousMustBeValue)


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1192,6 +1192,8 @@
   "String");
   verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n"
   "  bar) {}");
+  verifyFormat("function f(@Foo(Param) bar) {}", "function f(@Foo(Param)\n"
+ "  bar) {}");
   verifyFormat("a = true\n"
"return 1",
"a = true\n"
@@ -1557,7 +1559,7 @@
"}");
 }
 
-TEST_F(FormatTestJS, MetadataAnnotations) {
+TEST_F(FormatTestJS, Decorators) {
   verifyFormat("@A\nclass C {\n}");
   verifyFormat("@A({arg: 'value'})\nclass C {\n}");
   verifyFormat("@A\n@B\nclass C {\n}");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -18,6 +18,8 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 
+#include 
+
 #define DEBUG_TYPE "format-parser"
 
 namespace clang {
@@ -891,11 +893,14 @@
   bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
   bool PreviousStartsTemplateExpr =
   Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
-  if (PreviousMustBeValue && Line && Line->Tokens.size() > 1) {
-// If the token before the previous one is an '@', the previous token is an
-// annotation and can precede another identifier/value.
-const FormatToken *PrePrevious = std::prev(Line->Tokens.end(), 2)->Tok;
-if (PrePrevious->is(tok::at))
+  if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
+// If the line contains an '@' sign, the previous token might be an
+// annotation, which can 

[PATCH] D40424: clang-format: [JS] handle semis in generic types.

2017-11-24 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

TypeScript generic type arguments can contain object (literal) types,
which in turn can contain semicolons:

  const x: Array<{a: number; b: string;} = [];

Previously, clang-format would incorrectly categorize the braced list as
a block and terminate the line at the openening `{`, and then format the
entire expression badly.

With this change, clang-format recognizes `<` preceding a `{` as
introducing a type expression. In JS, `<` comparison with an object
literal can never be true, so the chance of introducing false positives
here is very low.


https://reviews.llvm.org/D40424

Files:
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1406,6 +1406,7 @@
   verifyFormat("function x(y: {a?: number;} = {}): number {\n"
"  return 12;\n"
"}");
+  verifyFormat("const x: Array<{a: number; b: string;}> = [];");
   verifyFormat("((a: string, b: number): string => a + b);");
   verifyFormat("var x: (y: number) => string;");
   verifyFormat("var x: P string>;");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -377,13 +377,16 @@
 switch (Tok->Tok.getKind()) {
 case tok::l_brace:
   if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
-if (PrevTok->is(tok::colon))
-  // A colon indicates this code is in a type, or a braced list
-  // following a label in an object literal ({a: {b: 1}}). The code
-  // below could be confused by semicolons between the individual
-  // members in a type member list, which would normally trigger
-  // BK_Block. In both cases, this must be parsed as an inline braced
-  // init.
+if (PrevTok->isOneOf(tok::colon, tok::less))
+  // A ':' indicates this code is in a type, or a braced list
+  // following a label in an object literal ({a: {b: 1}}).
+  // A '<' could be an object used in a comparison, but that is 
nonsense
+  // code (can never return true), so more likely it is a generic type
+  // argument (`X<{a: string; b: number}>`).
+  // The code below could be confused by semicolons between the
+  // individual members in a type member list, which would normally
+  // trigger BK_Block. In both cases, this must be parsed as an inline
+  // braced init.
   Tok->BlockKind = BK_BracedInit;
 else if (PrevTok->is(tok::r_paren))
   // `) { }` can only occur in function or method declarations in JS.


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1406,6 +1406,7 @@
   verifyFormat("function x(y: {a?: number;} = {}): number {\n"
"  return 12;\n"
"}");
+  verifyFormat("const x: Array<{a: number; b: string;}> = [];");
   verifyFormat("((a: string, b: number): string => a + b);");
   verifyFormat("var x: (y: number) => string;");
   verifyFormat("var x: P string>;");
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -377,13 +377,16 @@
 switch (Tok->Tok.getKind()) {
 case tok::l_brace:
   if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
-if (PrevTok->is(tok::colon))
-  // A colon indicates this code is in a type, or a braced list
-  // following a label in an object literal ({a: {b: 1}}). The code
-  // below could be confused by semicolons between the individual
-  // members in a type member list, which would normally trigger
-  // BK_Block. In both cases, this must be parsed as an inline braced
-  // init.
+if (PrevTok->isOneOf(tok::colon, tok::less))
+  // A ':' indicates this code is in a type, or a braced list
+  // following a label in an object literal ({a: {b: 1}}).
+  // A '<' could be an object used in a comparison, but that is nonsense
+  // code (can never return true), so more likely it is a generic type
+  // argument (`X<{a: string; b: number}>`).
+  // The code below could be confused by semicolons between the
+  // individual members in a type member list, which would normally
+  // trigger BK_Block. In both cases, this must be parsed as an inline
+  // braced init.
   Tok->BlockKind = BK_BracedInit;
 else if (PrevTok->is(tok::r_paren))
   // `) { }` can only occur 

[PATCH] D40410: clang-format: [JS] disable ASI on decorators.

2017-11-25 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL318973: clang-format: [JS] disable ASI on decorators. 
(authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D40410

Files:
  cfe/trunk/lib/Format/UnwrappedLineParser.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -18,6 +18,8 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 
+#include 
+
 #define DEBUG_TYPE "format-parser"
 
 namespace clang {
@@ -891,11 +893,14 @@
   bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
   bool PreviousStartsTemplateExpr =
   Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
-  if (PreviousMustBeValue && Line && Line->Tokens.size() > 1) {
-// If the token before the previous one is an '@', the previous token is an
-// annotation and can precede another identifier/value.
-const FormatToken *PrePrevious = std::prev(Line->Tokens.end(), 2)->Tok;
-if (PrePrevious->is(tok::at))
+  if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
+// If the line contains an '@' sign, the previous token might be an
+// annotation, which can precede another identifier/value.
+bool HasAt = std::find_if(Line->Tokens.begin(), Line->Tokens.end(),
+  [](UnwrappedLineNode &LineNode) {
+return LineNode.Tok->is(tok::at);
+  }) != Line->Tokens.end();
+if (HasAt)
   return;
   }
   if (Next->is(tok::exclaim) && PreviousMustBeValue)
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1197,6 +1197,8 @@
   "String");
   verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n"
   "  bar) {}");
+  verifyFormat("function f(@Foo(Param) bar) {}", "function f(@Foo(Param)\n"
+ "  bar) {}");
   verifyFormat("a = true\n"
"return 1",
"a = true\n"
@@ -1564,7 +1566,7 @@
"}");
 }
 
-TEST_F(FormatTestJS, MetadataAnnotations) {
+TEST_F(FormatTestJS, Decorators) {
   verifyFormat("@A\nclass C {\n}");
   verifyFormat("@A({arg: 'value'})\nclass C {\n}");
   verifyFormat("@A\n@B\nclass C {\n}");


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -18,6 +18,8 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 
+#include 
+
 #define DEBUG_TYPE "format-parser"
 
 namespace clang {
@@ -891,11 +893,14 @@
   bool PreviousMustBeValue = mustBeJSIdentOrValue(Keywords, Previous);
   bool PreviousStartsTemplateExpr =
   Previous->is(TT_TemplateString) && Previous->TokenText.endswith("${");
-  if (PreviousMustBeValue && Line && Line->Tokens.size() > 1) {
-// If the token before the previous one is an '@', the previous token is an
-// annotation and can precede another identifier/value.
-const FormatToken *PrePrevious = std::prev(Line->Tokens.end(), 2)->Tok;
-if (PrePrevious->is(tok::at))
+  if (PreviousMustBeValue || Previous->is(tok::r_paren)) {
+// If the line contains an '@' sign, the previous token might be an
+// annotation, which can precede another identifier/value.
+bool HasAt = std::find_if(Line->Tokens.begin(), Line->Tokens.end(),
+  [](UnwrappedLineNode &LineNode) {
+return LineNode.Tok->is(tok::at);
+  }) != Line->Tokens.end();
+if (HasAt)
   return;
   }
   if (Next->is(tok::exclaim) && PreviousMustBeValue)
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1197,6 +1197,8 @@
   "String");
   verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n"
   "  bar) {}");
+  verifyFormat("function f(@Foo(Param) bar) {}", "function f(@Foo(Param)\n"
+ "  bar) {}");
   verifyFormat("a = true\n"
"return 1",
"a = true\n"
@@ -1564,7 +1566,7 @@
"}");
 }
 
-TEST_F(FormatTestJS, MetadataAnnotations) {
+TEST_F(FormatTestJS, Decorators) {
   verifyFormat("@A\nclass C {\n}");
   verifyFormat("@A({arg: 'value'})\nclass C {\n}");
   v

[PATCH] D40424: clang-format: [JS] handle semis in generic types.

2017-11-25 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL318975: clang-format: [JS] handle semis in generic types. 
(authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D40424

Files:
  cfe/trunk/lib/Format/UnwrappedLineParser.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -379,13 +379,16 @@
 switch (Tok->Tok.getKind()) {
 case tok::l_brace:
   if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
-if (PrevTok->is(tok::colon))
-  // A colon indicates this code is in a type, or a braced list
-  // following a label in an object literal ({a: {b: 1}}). The code
-  // below could be confused by semicolons between the individual
-  // members in a type member list, which would normally trigger
-  // BK_Block. In both cases, this must be parsed as an inline braced
-  // init.
+if (PrevTok->isOneOf(tok::colon, tok::less))
+  // A ':' indicates this code is in a type, or a braced list
+  // following a label in an object literal ({a: {b: 1}}).
+  // A '<' could be an object used in a comparison, but that is 
nonsense
+  // code (can never return true), so more likely it is a generic type
+  // argument (`X<{a: string; b: number}>`).
+  // The code below could be confused by semicolons between the
+  // individual members in a type member list, which would normally
+  // trigger BK_Block. In both cases, this must be parsed as an inline
+  // braced init.
   Tok->BlockKind = BK_BracedInit;
 else if (PrevTok->is(tok::r_paren))
   // `) { }` can only occur in function or method declarations in JS.
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1414,6 +1414,7 @@
   verifyFormat("function x(y: {a?: number;} = {}): number {\n"
"  return 12;\n"
"}");
+  verifyFormat("const x: Array<{a: number; b: string;}> = [];");
   verifyFormat("((a: string, b: number): string => a + b);");
   verifyFormat("var x: (y: number) => string;");
   verifyFormat("var x: P string>;");


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -379,13 +379,16 @@
 switch (Tok->Tok.getKind()) {
 case tok::l_brace:
   if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
-if (PrevTok->is(tok::colon))
-  // A colon indicates this code is in a type, or a braced list
-  // following a label in an object literal ({a: {b: 1}}). The code
-  // below could be confused by semicolons between the individual
-  // members in a type member list, which would normally trigger
-  // BK_Block. In both cases, this must be parsed as an inline braced
-  // init.
+if (PrevTok->isOneOf(tok::colon, tok::less))
+  // A ':' indicates this code is in a type, or a braced list
+  // following a label in an object literal ({a: {b: 1}}).
+  // A '<' could be an object used in a comparison, but that is nonsense
+  // code (can never return true), so more likely it is a generic type
+  // argument (`X<{a: string; b: number}>`).
+  // The code below could be confused by semicolons between the
+  // individual members in a type member list, which would normally
+  // trigger BK_Block. In both cases, this must be parsed as an inline
+  // braced init.
   Tok->BlockKind = BK_BracedInit;
 else if (PrevTok->is(tok::r_paren))
   // `) { }` can only occur in function or method declarations in JS.
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1414,6 +1414,7 @@
   verifyFormat("function x(y: {a?: number;} = {}): number {\n"
"  return 12;\n"
"}");
+  verifyFormat("const x: Array<{a: number; b: string;}> = [];");
   verifyFormat("((a: string, b: number): string => a + b);");
   verifyFormat("var x: (y: number) => string;");
   verifyFormat("var x: P string>;");
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D40642: clang-format: [JS] do not wrap after async/await.

2017-11-30 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added subscribers: cfe-commits, klimek.

Otherwise automatic semicolon insertion can trigger, i.e. wrapping
produces invalid syntax.


Repository:
  rC Clang

https://reviews.llvm.org/D40642

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1152,6 +1152,11 @@
"const y = 3\n",
"const x = (   5 +9)\n"
"const y = 3\n");
+  // Ideally the foo() bit should be indented relative to the async function().
+  verifyFormat("async function\n"
+   "foo() {}",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2701,12 +2701,12 @@
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 const FormatToken *NonComment = Right.getPreviousNonComment();
 if (NonComment &&
-NonComment->isOneOf(tok::kw_return, Keywords.kw_yield, 
tok::kw_continue,
-tok::kw_break, tok::kw_throw, 
Keywords.kw_interface,
-Keywords.kw_type, tok::kw_static, tok::kw_public,
-tok::kw_private, tok::kw_protected,
-Keywords.kw_readonly, Keywords.kw_abstract,
-Keywords.kw_get, Keywords.kw_set))
+NonComment->isOneOf(
+tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break,
+tok::kw_throw, Keywords.kw_interface, Keywords.kw_type,
+tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected,
+Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get,
+Keywords.kw_set, Keywords.kw_async, Keywords.kw_await))
   return false; // Otherwise automatic semicolon insertion would trigger.
 if (Left.Tok.getIdentifierInfo() &&
 Right.startsSequence(tok::l_square, tok::r_square))


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1152,6 +1152,11 @@
"const y = 3\n",
"const x = (   5 +9)\n"
"const y = 3\n");
+  // Ideally the foo() bit should be indented relative to the async function().
+  verifyFormat("async function\n"
+   "foo() {}",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2701,12 +2701,12 @@
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 const FormatToken *NonComment = Right.getPreviousNonComment();
 if (NonComment &&
-NonComment->isOneOf(tok::kw_return, Keywords.kw_yield, tok::kw_continue,
-tok::kw_break, tok::kw_throw, Keywords.kw_interface,
-Keywords.kw_type, tok::kw_static, tok::kw_public,
-tok::kw_private, tok::kw_protected,
-Keywords.kw_readonly, Keywords.kw_abstract,
-Keywords.kw_get, Keywords.kw_set))
+NonComment->isOneOf(
+tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break,
+tok::kw_throw, Keywords.kw_interface, Keywords.kw_type,
+tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected,
+Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get,
+Keywords.kw_set, Keywords.kw_async, Keywords.kw_await))
   return false; // Otherwise automatic semicolon insertion would trigger.
 if (Left.Tok.getIdentifierInfo() &&
 Right.startsSequence(tok::l_square, tok::r_square))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D40642: clang-format: [JS] do not wrap after async/await.

2017-11-30 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL319415: clang-format: [JS] do not wrap after async/await. 
(authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D40642

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2701,12 +2701,12 @@
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 const FormatToken *NonComment = Right.getPreviousNonComment();
 if (NonComment &&
-NonComment->isOneOf(tok::kw_return, Keywords.kw_yield, 
tok::kw_continue,
-tok::kw_break, tok::kw_throw, 
Keywords.kw_interface,
-Keywords.kw_type, tok::kw_static, tok::kw_public,
-tok::kw_private, tok::kw_protected,
-Keywords.kw_readonly, Keywords.kw_abstract,
-Keywords.kw_get, Keywords.kw_set))
+NonComment->isOneOf(
+tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break,
+tok::kw_throw, Keywords.kw_interface, Keywords.kw_type,
+tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected,
+Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get,
+Keywords.kw_set, Keywords.kw_async, Keywords.kw_await))
   return false; // Otherwise automatic semicolon insertion would trigger.
 if (Left.Tok.getIdentifierInfo() &&
 Right.startsSequence(tok::l_square, tok::r_square))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1152,6 +1152,11 @@
"const y = 3\n",
"const x = (   5 +9)\n"
"const y = 3\n");
+  // Ideally the foo() bit should be indented relative to the async function().
+  verifyFormat("async function\n"
+   "foo() {}",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2701,12 +2701,12 @@
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 const FormatToken *NonComment = Right.getPreviousNonComment();
 if (NonComment &&
-NonComment->isOneOf(tok::kw_return, Keywords.kw_yield, tok::kw_continue,
-tok::kw_break, tok::kw_throw, Keywords.kw_interface,
-Keywords.kw_type, tok::kw_static, tok::kw_public,
-tok::kw_private, tok::kw_protected,
-Keywords.kw_readonly, Keywords.kw_abstract,
-Keywords.kw_get, Keywords.kw_set))
+NonComment->isOneOf(
+tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break,
+tok::kw_throw, Keywords.kw_interface, Keywords.kw_type,
+tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected,
+Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get,
+Keywords.kw_set, Keywords.kw_async, Keywords.kw_await))
   return false; // Otherwise automatic semicolon insertion would trigger.
 if (Left.Tok.getIdentifierInfo() &&
 Right.startsSequence(tok::l_square, tok::r_square))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1152,6 +1152,11 @@
"const y = 3\n",
"const x = (   5 +9)\n"
"const y = 3\n");
+  // Ideally the foo() bit should be indented relative to the async function().
+  verifyFormat("async function\n"
+   "foo() {}",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66736: clang-format: [JS] handle `as const`.

2019-08-26 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
Herald added a project: clang.

TypeScript 3.4 supports casting into a const type using `as const`:

  const x = {x: 1} as const;

Previously, clang-format would insert a space after the `const`. With
this patch, no space is inserted after the sequence `as const`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D66736

Files:
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -1479,6 +1479,9 @@
   ".someFunction(aa);");
   verifyFormat("const xIsALongIdent:\n""YJustBarelyFitsLinex[];",
   getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = {\n"
+   "  y: 1\n"
+   "} as const;");
 }
 
 TEST_F(FormatTestJS, UnionIntersectionTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2746,6 +2746,10 @@
tok::kw_void))
 return true;
 }
+// `foo as const;` casts into a const type.
+if (Left.endsSequence(tok::kw_const, Keywords.kw_as)) {
+  return false;
+}
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -1479,6 +1479,9 @@
   ".someFunction(aa);");
   verifyFormat("const xIsALongIdent:\n""YJustBarelyFitsLinex[];",
   getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = {\n"
+   "  y: 1\n"
+   "} as const;");
 }
 
 TEST_F(FormatTestJS, UnionIntersectionTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2746,6 +2746,10 @@
tok::kw_void))
 return true;
 }
+// `foo as const;` casts into a const type.
+if (Left.endsSequence(tok::kw_const, Keywords.kw_as)) {
+  return false;
+}
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66736: clang-format: [JS] handle `as const`.

2019-08-26 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG5836472ac488: clang-format: [JS] handle `as const`. 
(authored by mprobst).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66736/new/

https://reviews.llvm.org/D66736

Files:
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -1479,6 +1479,9 @@
   ".someFunction(aa);");
   verifyFormat("const xIsALongIdent:\n""YJustBarelyFitsLinex[];",
   getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = {\n"
+   "  y: 1\n"
+   "} as const;");
 }
 
 TEST_F(FormatTestJS, UnionIntersectionTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2746,6 +2746,10 @@
tok::kw_void))
 return true;
 }
+// `foo as const;` casts into a const type.
+if (Left.endsSequence(tok::kw_const, Keywords.kw_as)) {
+  return false;
+}
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -1479,6 +1479,9 @@
   ".someFunction(aa);");
   verifyFormat("const xIsALongIdent:\n""YJustBarelyFitsLinex[];",
   getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = {\n"
+   "  y: 1\n"
+   "} as const;");
 }
 
 TEST_F(FormatTestJS, UnionIntersectionTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2746,6 +2746,10 @@
tok::kw_void))
 return true;
 }
+// `foo as const;` casts into a const type.
+if (Left.endsSequence(tok::kw_const, Keywords.kw_as)) {
+  return false;
+}
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36131: clang-format: [JS] handle object types in extends positions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

clang-format would previously drop the whitespace after `extends` in code such 
as:

  class Foo extends {} {}

Where the first set of curly braces is an inline object literal type.


https://reviews.llvm.org/D36131

Files:
  lib/Format/TokenAnnotator.cpp
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1400,6 +1400,17 @@
"}");
 }
 
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+  verifyFormat("class C extends {} {}");
+  verifyFormat("class C implements {bar: number} {}");
+  // Somewhat odd, but probably closest to reasonable formatting?
+  verifyFormat("class C implements {\n"
+   "  bar: number,\n"
+   "  baz: string,\n"
+   "} {}");
+  verifyFormat("class C {}");
+}
+
 TEST_F(FormatTestJS, EnumDeclarations) {
   verifyFormat("enum Foo {\n"
"  A = 1,\n"
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -1970,6 +1970,17 @@
  ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
   FormatTok->isOneOf(tok::period, tok::comma))) {
+if (Style.Language == FormatStyle::LK_JavaScript &&
+FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+  // JavaScript/TypeScript supports inline object types in
+  // extends/implements positions:
+  // class Foo implements {bar: number} { }
+  nextToken();
+  if (FormatTok->is(tok::l_brace)) {
+tryToParseBracedList();
+continue;
+  }
+}
 bool IsNonMacroIdentifier =
 FormatTok->is(tok::identifier) &&
 FormatTok->TokenText != FormatTok->TokenText.upper();
@@ -1989,7 +2000,7 @@
   // and thus rule out the record production in case there is no template
   // (this would still leave us with an ambiguity between template function
   // and class declarations).
-  if (FormatTok->isOneOf(tok::colon, tok::less)) {
+  if (FormatTok->isOneOf(tok::colon, tok::less, Keywords.kw_extends)) {
 while (!eof()) {
   if (FormatTok->is(tok::l_brace)) {
 calculateBraceTypes(/*ExpectClassBody=*/true);
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2341,7 +2341,8 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
   return false;
 if (Right.isOneOf(tok::l_brace, tok::l_square) &&
-Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
+Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
+ Keywords.kw_extends, Keywords.kw_implements))
   return true;
 // JS methods can use some keywords as names (e.g. `delete()`).
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1400,6 +1400,17 @@
"}");
 }
 
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+  verifyFormat("class C extends {} {}");
+  verifyFormat("class C implements {bar: number} {}");
+  // Somewhat odd, but probably closest to reasonable formatting?
+  verifyFormat("class C implements {\n"
+   "  bar: number,\n"
+   "  baz: string,\n"
+   "} {}");
+  verifyFormat("class C {}");
+}
+
 TEST_F(FormatTestJS, EnumDeclarations) {
   verifyFormat("enum Foo {\n"
"  A = 1,\n"
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -1970,6 +1970,17 @@
  ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
   FormatTok->isOneOf(tok::period, tok::comma))) {
+if (Style.Language == FormatStyle::LK_JavaScript &&
+FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+  // JavaScript/TypeScript supports inline object types in
+  // extends/implements positions:
+  // class Foo implements {bar: number} { }
+  nextToken();
+  if (FormatTok->is(tok::l_brace)) {
+tryToParseBracedList();
+continue;
+  }
+}
 bool IsNonMacroIdentifier =
 FormatTok->is(tok::identifier) &&
 FormatTok->TokenText != FormatTok->TokenText.upper();
@@ -1989,7 +2000,7 @@
   // and thus rule out the record production in case there is no template
   // (this would still 

[PATCH] D36132: clang-format: [JS] support default imports.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

Formerly, `import {default as X} from y;` would not be recognized as an import.


https://reviews.llvm.org/D36132

Files:
  lib/Format/SortJavaScriptImports.cpp
  unittests/Format/SortImportsTestJS.cpp


Index: unittests/Format/SortImportsTestJS.cpp
===
--- unittests/Format/SortImportsTestJS.cpp
+++ unittests/Format/SortImportsTestJS.cpp
@@ -300,6 +300,14 @@
  "1;");
 }
 
+TEST_F(SortImportsTestJS, SortDefaultImports) {
+  // Reproduces issue where multi-line import was not parsed correctly.
+  verifySort("import {A} from 'a';\n"
+ "import {default as B} from 'b';\n",
+ "import {default as B} from 'b';\n"
+ "import {A} from 'a';\n");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/SortJavaScriptImports.cpp
===
--- lib/Format/SortJavaScriptImports.cpp
+++ lib/Format/SortJavaScriptImports.cpp
@@ -413,7 +413,7 @@
   nextToken();
   if (Current->is(tok::r_brace))
 break;
-  if (Current->isNot(tok::identifier))
+  if (Current->isNot(tok::identifier) && Current->isNot(tok::kw_default))
 return false;
 
   JsImportedSymbol Symbol;
@@ -425,7 +425,7 @@
 
   if (Current->is(Keywords.kw_as)) {
 nextToken();
-if (Current->isNot(tok::identifier))
+if (Current->isNot(tok::identifier) && Current->isNot(tok::kw_default))
   return false;
 Symbol.Alias = Current->TokenText;
 nextToken();


Index: unittests/Format/SortImportsTestJS.cpp
===
--- unittests/Format/SortImportsTestJS.cpp
+++ unittests/Format/SortImportsTestJS.cpp
@@ -300,6 +300,14 @@
  "1;");
 }
 
+TEST_F(SortImportsTestJS, SortDefaultImports) {
+  // Reproduces issue where multi-line import was not parsed correctly.
+  verifySort("import {A} from 'a';\n"
+ "import {default as B} from 'b';\n",
+ "import {default as B} from 'b';\n"
+ "import {A} from 'a';\n");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/SortJavaScriptImports.cpp
===
--- lib/Format/SortJavaScriptImports.cpp
+++ lib/Format/SortJavaScriptImports.cpp
@@ -413,7 +413,7 @@
   nextToken();
   if (Current->is(tok::r_brace))
 break;
-  if (Current->isNot(tok::identifier))
+  if (Current->isNot(tok::identifier) && Current->isNot(tok::kw_default))
 return false;
 
   JsImportedSymbol Symbol;
@@ -425,7 +425,7 @@
 
   if (Current->is(Keywords.kw_as)) {
 nextToken();
-if (Current->isNot(tok::identifier))
+if (Current->isNot(tok::identifier) && Current->isNot(tok::kw_default))
   return false;
 Symbol.Alias = Current->TokenText;
 nextToken();
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36131: clang-format: [JS] handle object types in extends positions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 109078.
mprobst added a comment.

- revert bogus change


https://reviews.llvm.org/D36131

Files:
  lib/Format/TokenAnnotator.cpp
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1400,6 +1400,17 @@
"}");
 }
 
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+  verifyFormat("class C extends {} {}");
+  verifyFormat("class C implements {bar: number} {}");
+  // Somewhat odd, but probably closest to reasonable formatting?
+  verifyFormat("class C implements {\n"
+   "  bar: number,\n"
+   "  baz: string,\n"
+   "} {}");
+  verifyFormat("class C {}");
+}
+
 TEST_F(FormatTestJS, EnumDeclarations) {
   verifyFormat("enum Foo {\n"
"  A = 1,\n"
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -1970,6 +1970,17 @@
  ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
   FormatTok->isOneOf(tok::period, tok::comma))) {
+if (Style.Language == FormatStyle::LK_JavaScript &&
+FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+  // JavaScript/TypeScript supports inline object types in
+  // extends/implements positions:
+  // class Foo implements {bar: number} { }
+  nextToken();
+  if (FormatTok->is(tok::l_brace)) {
+tryToParseBracedList();
+continue;
+  }
+}
 bool IsNonMacroIdentifier =
 FormatTok->is(tok::identifier) &&
 FormatTok->TokenText != FormatTok->TokenText.upper();
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2341,7 +2341,8 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
   return false;
 if (Right.isOneOf(tok::l_brace, tok::l_square) &&
-Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
+Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
+ Keywords.kw_extends, Keywords.kw_implements))
   return true;
 // JS methods can use some keywords as names (e.g. `delete()`).
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1400,6 +1400,17 @@
"}");
 }
 
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+  verifyFormat("class C extends {} {}");
+  verifyFormat("class C implements {bar: number} {}");
+  // Somewhat odd, but probably closest to reasonable formatting?
+  verifyFormat("class C implements {\n"
+   "  bar: number,\n"
+   "  baz: string,\n"
+   "} {}");
+  verifyFormat("class C {}");
+}
+
 TEST_F(FormatTestJS, EnumDeclarations) {
   verifyFormat("enum Foo {\n"
"  A = 1,\n"
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -1970,6 +1970,17 @@
  ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
   FormatTok->isOneOf(tok::period, tok::comma))) {
+if (Style.Language == FormatStyle::LK_JavaScript &&
+FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+  // JavaScript/TypeScript supports inline object types in
+  // extends/implements positions:
+  // class Foo implements {bar: number} { }
+  nextToken();
+  if (FormatTok->is(tok::l_brace)) {
+tryToParseBracedList();
+continue;
+  }
+}
 bool IsNonMacroIdentifier =
 FormatTok->is(tok::identifier) &&
 FormatTok->TokenText != FormatTok->TokenText.upper();
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2341,7 +2341,8 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
   return false;
 if (Right.isOneOf(tok::l_brace, tok::l_square) &&
-Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
+Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
+ Keywords.kw_extends, Keywords.kw_implements))
   return true;
 // JS methods can use some keywords as names (e.g. `delete()`).
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
__

[PATCH] D36139: clang-format: [JS] prefer wrapping chains over empty literals.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

E.g. don't wrap like this:

  (foo.bar.baz).and.bam(Blah.of({
  }))

But rather:

  (foo.bar.baz)
  .and.bam(Blah.of({}))


https://reviews.llvm.org/D36139

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -832,6 +832,15 @@
 
 }
 
+TEST_F(FormatTestJS, DontWrapEmptyLiterals) {
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of([]));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of({}));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of(()));");
+}
+
 TEST_F(FormatTestJS, InliningFunctionLiterals) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2005,6 +2005,11 @@
 if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return 100;
+// Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
+if ((Left.is(tok::l_brace) && Right.is(tok::r_brace)) ||
+(Left.is(tok::l_square) && Right.is(tok::r_square)) ||
+(Left.is(tok::l_paren) && Right.is(tok::r_paren)))
+  return 200;
   }
 
   if (Right.is(tok::identifier) && Right.Next && 
Right.Next->is(TT_DictLiteral))


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -832,6 +832,15 @@
 
 }
 
+TEST_F(FormatTestJS, DontWrapEmptyLiterals) {
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of([]));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of({}));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of(()));");
+}
+
 TEST_F(FormatTestJS, InliningFunctionLiterals) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2005,6 +2005,11 @@
 if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return 100;
+// Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
+if ((Left.is(tok::l_brace) && Right.is(tok::r_brace)) ||
+(Left.is(tok::l_square) && Right.is(tok::r_square)) ||
+(Left.is(tok::l_paren) && Right.is(tok::r_paren)))
+  return 200;
   }
 
   if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36142: clang-format: [JS] do not insert whitespace in call positions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

In JavaScript, may keywords can be used in method names and thus call sites:

  foo.delete();
  foo.instanceof();

clang-format would previously insert whitespace after the `instanceof`. This
change generically skips inserting whitespace between a keyword and a
parenthesis if preceded by a dot, i.e. in a callsite.


https://reviews.llvm.org/D36142

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -232,6 +232,7 @@
   verifyFormat("x.var() = 1;");
   verifyFormat("x.for() = 1;");
   verifyFormat("x.as() = 1;");
+  verifyFormat("x.instanceof() = 1;");
   verifyFormat("x = {\n"
"  a: 12,\n"
"  interface: 1,\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2347,6 +2347,11 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+// Valid JS method names can include keywords, e.g. `foo.delete()` or
+// `bar.instanceof()`.
+if (Right.is(tok::l_paren) && Left.Tok.getIdentifierInfo() &&
+Left.Previous && Left.Previous->is(tok::period))
+  return false;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -232,6 +232,7 @@
   verifyFormat("x.var() = 1;");
   verifyFormat("x.for() = 1;");
   verifyFormat("x.as() = 1;");
+  verifyFormat("x.instanceof() = 1;");
   verifyFormat("x = {\n"
"  a: 12,\n"
"  interface: 1,\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2347,6 +2347,11 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+// Valid JS method names can include keywords, e.g. `foo.delete()` or
+// `bar.instanceof()`.
+if (Right.is(tok::l_paren) && Left.Tok.getIdentifierInfo() &&
+Left.Previous && Left.Previous->is(tok::period))
+  return false;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36142: clang-format: [JS] do not insert whitespace in call positions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 109089.
mprobst added a comment.

- support switch, case, delete.


https://reviews.llvm.org/D36142

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -232,6 +232,9 @@
   verifyFormat("x.var() = 1;");
   verifyFormat("x.for() = 1;");
   verifyFormat("x.as() = 1;");
+  verifyFormat("x.instanceof() = 1;");
+  verifyFormat("x.switch() = 1;");
+  verifyFormat("x.case() = 1;");
   verifyFormat("x = {\n"
"  a: 12,\n"
"  interface: 1,\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2347,6 +2347,13 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+// Valid JS method names can include keywords, e.g. `foo.delete()` or
+// `bar.instanceof()`.
+if (Right.is(tok::l_paren) && Left.Previous &&
+Left.Previous->is(tok::period) &&
+(Left.Tok.getIdentifierInfo() ||
+ Left.isOneOf(tok::kw_switch, tok::kw_case, tok::kw_delete)))
+  return false;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -232,6 +232,9 @@
   verifyFormat("x.var() = 1;");
   verifyFormat("x.for() = 1;");
   verifyFormat("x.as() = 1;");
+  verifyFormat("x.instanceof() = 1;");
+  verifyFormat("x.switch() = 1;");
+  verifyFormat("x.case() = 1;");
   verifyFormat("x = {\n"
"  a: 12,\n"
"  interface: 1,\n"
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2347,6 +2347,13 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+// Valid JS method names can include keywords, e.g. `foo.delete()` or
+// `bar.instanceof()`.
+if (Right.is(tok::l_paren) && Left.Previous &&
+Left.Previous->is(tok::period) &&
+(Left.Tok.getIdentifierInfo() ||
+ Left.isOneOf(tok::kw_switch, tok::kw_case, tok::kw_delete)))
+  return false;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36144: clang-format: [JS] consistenly format enums.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

Previously, const enums would get formatted differently because the modifier 
was not recognized.


https://reviews.llvm.org/D36144

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1414,6 +1414,14 @@
"  B\n"
"}\n"
"var x = 1;");
+  verifyFormat("const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
+  verifyFormat("export const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
 }
 
 TEST_F(FormatTestJS, MetadataAnnotations) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2516,7 +2516,9 @@
   return true;
 if (Left.is(tok::l_brace) && Line.Level == 0 &&
 (Line.startsWith(tok::kw_enum) ||
- Line.startsWith(tok::kw_export, tok::kw_enum)))
+ Line.startsWith(tok::kw_const, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum)))
   // JavaScript top-level enum key/value pairs are put on separate lines
   // instead of bin-packing.
   return true;


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1414,6 +1414,14 @@
"  B\n"
"}\n"
"var x = 1;");
+  verifyFormat("const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
+  verifyFormat("export const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
 }
 
 TEST_F(FormatTestJS, MetadataAnnotations) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2516,7 +2516,9 @@
   return true;
 if (Left.is(tok::l_brace) && Line.Level == 0 &&
 (Line.startsWith(tok::kw_enum) ||
- Line.startsWith(tok::kw_export, tok::kw_enum)))
+ Line.startsWith(tok::kw_const, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum)))
   // JavaScript top-level enum key/value pairs are put on separate lines
   // instead of bin-packing.
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36146: clang-format: [JS] whitespace between keywords and parenthesized expressions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

`throw (...)` should have a whitespace following it, as do await and void.


https://reviews.llvm.org/D36146

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -259,6 +259,15 @@
   "}\n");
 }
 
+TEST_F(FormatTestJS, ReservedWordsParenthesized) {
+  // All of these are statements using the keyword, not function calls.
+  verifyFormat("throw (x + y);\n"
+   "await (await x).y;\n"
+   "void (0);\n"
+   "delete (x.y);\n"
+   "return (x);\n");
+}
+
 TEST_F(FormatTestJS, CppKeywords) {
   // Make sure we don't mess stuff up because of C++ keywords.
   verifyFormat("return operator && (aa);");
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2347,6 +2347,9 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+if (Right.is(tok::l_paren) &&
+Left.isOneOf(tok::kw_throw, Keywords.kw_await, tok::kw_void))
+  return true;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -259,6 +259,15 @@
   "}\n");
 }
 
+TEST_F(FormatTestJS, ReservedWordsParenthesized) {
+  // All of these are statements using the keyword, not function calls.
+  verifyFormat("throw (x + y);\n"
+   "await (await x).y;\n"
+   "void (0);\n"
+   "delete (x.y);\n"
+   "return (x);\n");
+}
+
 TEST_F(FormatTestJS, CppKeywords) {
   // Make sure we don't mess stuff up because of C++ keywords.
   verifyFormat("return operator && (aa);");
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2347,6 +2347,9 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+if (Right.is(tok::l_paren) &&
+Left.isOneOf(tok::kw_throw, Keywords.kw_await, tok::kw_void))
+  return true;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36147: clang-format: [JS] handle union types in arrow functions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

clang-format would previously fail to detect that an arrow functions parameter 
block is not an expression, and thus insert whitespace around the `|` and `&` 
type operators in it.


https://reviews.llvm.org/D36147

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -988,6 +988,9 @@
".doSomethingElse(\n"
"// break\n"
");");
+  verifyFormat("const f = (x: string|null): string|null => {\n"
+   "  return x;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReturnStatements) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -533,6 +533,7 @@
 Contexts.back().ContextKind == tok::l_square || // array type
 (Contexts.size() == 1 &&
  Line.MustBeDeclaration)) { // method/property declaration
+  Contexts.back().IsExpression = false;
   Tok->Type = TT_JsTypeColon;
   break;
 }


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -988,6 +988,9 @@
".doSomethingElse(\n"
"// break\n"
");");
+  verifyFormat("const f = (x: string|null): string|null => {\n"
+   "  return x;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReturnStatements) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -533,6 +533,7 @@
 Contexts.back().ContextKind == tok::l_square || // array type
 (Contexts.size() == 1 &&
  Line.MustBeDeclaration)) { // method/property declaration
+  Contexts.back().IsExpression = false;
   Tok->Type = TT_JsTypeColon;
   break;
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36148: clang-format: [JS] support fields with case/switch/default labels.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

`case:` and `default:` would normally parse as labels for a `switch` block.
However in TypeScript, they can be used in field declarations, e.g.:

  interface I {
case: string;
  }

This change special cases parsing them in declaration lines to avoid wrapping
them.


https://reviews.llvm.org/D36148

Files:
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -242,6 +242,12 @@
   verifyFormat("var interface = 2;");
   verifyFormat("interface = 2;");
   verifyFormat("x = interface instanceof y;");
+  verifyFormat("interface Test {\n"
+   "  x: string;\n"
+   "  switch: string;\n"
+   "  case: string;\n"
+   "  default: string;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReservedWordsMethods) {
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -326,6 +326,11 @@
   break;
 case tok::kw_default:
 case tok::kw_case:
+  if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration) {
+// A 'case: string' style field declaration.
+parseStructuralElement();
+break;
+  }
   if (!SwitchLabelEncountered &&
   (Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 
1)))
 ++Line->Level;
@@ -953,13 +958,22 @@
 parseDoWhile();
 return;
   case tok::kw_switch:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // 'switch: string' field declaration.
+  break;
 parseSwitch();
 return;
   case tok::kw_default:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // 'default: string' field declaration.
+  break;
 nextToken();
 parseLabel();
 return;
   case tok::kw_case:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // 'case: string' field declaration.
+  break;
 parseCaseLabel();
 return;
   case tok::kw_try:


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -242,6 +242,12 @@
   verifyFormat("var interface = 2;");
   verifyFormat("interface = 2;");
   verifyFormat("x = interface instanceof y;");
+  verifyFormat("interface Test {\n"
+   "  x: string;\n"
+   "  switch: string;\n"
+   "  case: string;\n"
+   "  default: string;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReservedWordsMethods) {
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -326,6 +326,11 @@
   break;
 case tok::kw_default:
 case tok::kw_case:
+  if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration) {
+// A 'case: string' style field declaration.
+parseStructuralElement();
+break;
+  }
   if (!SwitchLabelEncountered &&
   (Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1)))
 ++Line->Level;
@@ -953,13 +958,22 @@
 parseDoWhile();
 return;
   case tok::kw_switch:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // 'switch: string' field declaration.
+  break;
 parseSwitch();
 return;
   case tok::kw_default:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // 'default: string' field declaration.
+  break;
 nextToken();
 parseLabel();
 return;
   case tok::kw_case:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // 'case: string' field declaration.
+  break;
 parseCaseLabel();
 return;
   case tok::kw_try:
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36131: clang-format: [JS] handle object types in extends positions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL309695: clang-format: [JS] handle object types in extends 
positions. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36131

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/lib/Format/UnwrappedLineParser.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1400,6 +1400,17 @@
"}");
 }
 
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+  verifyFormat("class C extends {} {}");
+  verifyFormat("class C implements {bar: number} {}");
+  // Somewhat odd, but probably closest to reasonable formatting?
+  verifyFormat("class C implements {\n"
+   "  bar: number,\n"
+   "  baz: string,\n"
+   "} {}");
+  verifyFormat("class C {}");
+}
+
 TEST_F(FormatTestJS, EnumDeclarations) {
   verifyFormat("enum Foo {\n"
"  A = 1,\n"
Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2341,7 +2341,8 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
   return false;
 if (Right.isOneOf(tok::l_brace, tok::l_square) &&
-Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
+Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
+ Keywords.kw_extends, Keywords.kw_implements))
   return true;
 // JS methods can use some keywords as names (e.g. `delete()`).
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -1970,6 +1970,17 @@
  ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
   FormatTok->isOneOf(tok::period, tok::comma))) {
+if (Style.Language == FormatStyle::LK_JavaScript &&
+FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+  // JavaScript/TypeScript supports inline object types in
+  // extends/implements positions:
+  // class Foo implements {bar: number} { }
+  nextToken();
+  if (FormatTok->is(tok::l_brace)) {
+tryToParseBracedList();
+continue;
+  }
+}
 bool IsNonMacroIdentifier =
 FormatTok->is(tok::identifier) &&
 FormatTok->TokenText != FormatTok->TokenText.upper();


Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1400,6 +1400,17 @@
"}");
 }
 
+TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
+  verifyFormat("class C extends {} {}");
+  verifyFormat("class C implements {bar: number} {}");
+  // Somewhat odd, but probably closest to reasonable formatting?
+  verifyFormat("class C implements {\n"
+   "  bar: number,\n"
+   "  baz: string,\n"
+   "} {}");
+  verifyFormat("class C {}");
+}
+
 TEST_F(FormatTestJS, EnumDeclarations) {
   verifyFormat("enum Foo {\n"
"  A = 1,\n"
Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2341,7 +2341,8 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
   return false;
 if (Right.isOneOf(tok::l_brace, tok::l_square) &&
-Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
+Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
+ Keywords.kw_extends, Keywords.kw_implements))
   return true;
 // JS methods can use some keywords as names (e.g. `delete()`).
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -1970,6 +1970,17 @@
  ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
   FormatTok->isOneOf(tok::period, tok::comma))) {
+if (Style.Language == FormatStyle::LK_JavaScript &&
+FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
+  // JavaScript/TypeScript supports inline object types in
+  // extends/implements positions:
+  // class Foo implements {bar: num

[PATCH] D36132: clang-format: [JS] support default imports.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL309697: clang-format: [JS] support default imports. 
(authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D36132?vs=109059&id=109136#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D36132

Files:
  cfe/trunk/lib/Format/SortJavaScriptImports.cpp
  cfe/trunk/unittests/Format/SortImportsTestJS.cpp


Index: cfe/trunk/lib/Format/SortJavaScriptImports.cpp
===
--- cfe/trunk/lib/Format/SortJavaScriptImports.cpp
+++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp
@@ -413,7 +413,7 @@
   nextToken();
   if (Current->is(tok::r_brace))
 break;
-  if (Current->isNot(tok::identifier))
+  if (!Current->isOneOf(tok::identifier, tok::kw_default))
 return false;
 
   JsImportedSymbol Symbol;
@@ -425,7 +425,7 @@
 
   if (Current->is(Keywords.kw_as)) {
 nextToken();
-if (Current->isNot(tok::identifier))
+if (!Current->isOneOf(tok::identifier, tok::kw_default))
   return false;
 Symbol.Alias = Current->TokenText;
 nextToken();
Index: cfe/trunk/unittests/Format/SortImportsTestJS.cpp
===
--- cfe/trunk/unittests/Format/SortImportsTestJS.cpp
+++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp
@@ -300,6 +300,14 @@
  "1;");
 }
 
+TEST_F(SortImportsTestJS, SortDefaultImports) {
+  // Reproduces issue where multi-line import was not parsed correctly.
+  verifySort("import {A} from 'a';\n"
+ "import {default as B} from 'b';\n",
+ "import {default as B} from 'b';\n"
+ "import {A} from 'a';\n");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang


Index: cfe/trunk/lib/Format/SortJavaScriptImports.cpp
===
--- cfe/trunk/lib/Format/SortJavaScriptImports.cpp
+++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp
@@ -413,7 +413,7 @@
   nextToken();
   if (Current->is(tok::r_brace))
 break;
-  if (Current->isNot(tok::identifier))
+  if (!Current->isOneOf(tok::identifier, tok::kw_default))
 return false;
 
   JsImportedSymbol Symbol;
@@ -425,7 +425,7 @@
 
   if (Current->is(Keywords.kw_as)) {
 nextToken();
-if (Current->isNot(tok::identifier))
+if (!Current->isOneOf(tok::identifier, tok::kw_default))
   return false;
 Symbol.Alias = Current->TokenText;
 nextToken();
Index: cfe/trunk/unittests/Format/SortImportsTestJS.cpp
===
--- cfe/trunk/unittests/Format/SortImportsTestJS.cpp
+++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp
@@ -300,6 +300,14 @@
  "1;");
 }
 
+TEST_F(SortImportsTestJS, SortDefaultImports) {
+  // Reproduces issue where multi-line import was not parsed correctly.
+  verifySort("import {A} from 'a';\n"
+ "import {default as B} from 'b';\n",
+ "import {default as B} from 'b';\n"
+ "import {A} from 'a';\n");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36159: clang-format: [JS] handle single lines comments ending in `\\`.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

Previously, clang-format would consider the following code line to be part of
the comment and incorrectly format the rest of the file.


https://reviews.llvm.org/D36159

Files:
  lib/Format/FormatTokenLexer.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2038,5 +2038,27 @@
"};", FourSpaces);
 }
 
+TEST_F(FormatTestJS, BackslashesInComments) {
+  verifyFormat("// hello \\\n"
+   "if (x) foo();\n",
+   "// hello \\\n"
+   " if ( x) \n"
+   "   foo();\n");
+  verifyFormat("/* ignore \\\n"
+   " */\n"
+   "if (x) foo();\n",
+   "/* ignore \\\n"
+   " */\n"
+   " if (  x) foo();\n");
+  verifyFormat("// st \\ art\\\n"
+   "// comment"
+   "// continue \\\n"
+   "formatMe();\n",
+   "// st \\ art\\\n"
+   "// comment"
+   "// continue \\\n"
+   "formatMe( );\n");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/FormatTokenLexer.cpp
===
--- lib/Format/FormatTokenLexer.cpp
+++ lib/Format/FormatTokenLexer.cpp
@@ -529,6 +529,34 @@
 readRawToken(*FormatTok);
   }
 
+  // JavaScript and Java do not allow to escape the end of the line with a
+  // backslash. Backslashes are syntax errors in plain source, but can occur in
+  // comments. When a single line comment ends with a \, it'll cause the next
+  // line of code to be lexed as a comment, breaking formatting. The code below
+  // finds comments that contain a backslash followed by a line break, 
truncates
+  // the comment token at the backslash, and resets the lexer to restart behind
+  // the backslash.
+  if ((Style.Language == FormatStyle::LK_JavaScript ||
+   Style.Language == FormatStyle::LK_Java) &&
+  FormatTok->is(tok::comment) && FormatTok->TokenText.startswith("//")) {
+size_t BackslashPos = FormatTok->TokenText.find('\\');
+while (BackslashPos != StringRef::npos) {
+  if (BackslashPos + 1 < FormatTok->TokenText.size() &&
+  FormatTok->TokenText[BackslashPos + 1] == '\n') {
+const char *Offset = Lex->getBufferLocation();
+Offset -= FormatTok->TokenText.size();
+Offset += BackslashPos + 1;
+resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
+FormatTok->TokenText = FormatTok->TokenText.substr(0, BackslashPos + 
1);
+FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
+FormatTok->TokenText, FormatTok->OriginalColumn, Style.TabWidth,
+Encoding);
+break;
+  }
+  BackslashPos = FormatTok->TokenText.find('\\', BackslashPos + 1);
+}
+  }
+
   // In case the token starts with escaped newlines, we want to
   // take them into account as whitespace - this pattern is quite frequent
   // in macro definitions.


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -2038,5 +2038,27 @@
"};", FourSpaces);
 }
 
+TEST_F(FormatTestJS, BackslashesInComments) {
+  verifyFormat("// hello \\\n"
+   "if (x) foo();\n",
+   "// hello \\\n"
+   " if ( x) \n"
+   "   foo();\n");
+  verifyFormat("/* ignore \\\n"
+   " */\n"
+   "if (x) foo();\n",
+   "/* ignore \\\n"
+   " */\n"
+   " if (  x) foo();\n");
+  verifyFormat("// st \\ art\\\n"
+   "// comment"
+   "// continue \\\n"
+   "formatMe();\n",
+   "// st \\ art\\\n"
+   "// comment"
+   "// continue \\\n"
+   "formatMe( );\n");
+}
+
 } // end namespace tooling
 } // end namespace clang
Index: lib/Format/FormatTokenLexer.cpp
===
--- lib/Format/FormatTokenLexer.cpp
+++ lib/Format/FormatTokenLexer.cpp
@@ -529,6 +529,34 @@
 readRawToken(*FormatTok);
   }
 
+  // JavaScript and Java do not allow to escape the end of the line with a
+  // backslash. Backslashes are syntax errors in plain source, but can occur in
+  // comments. When a single line comment ends with a \, it'll cause the next
+  // line of code to be lexed as a comment, breaking formatting. The code below
+  // finds comments that contain a backslash followed by a line break, truncates
+  // the comment token at the backslash, and resets the lexer to restart behind
+  // the backslash.
+  if ((Style.Language == FormatStyle::LK_JavaScript ||
+   Style.Language == FormatSty

[PATCH] D36144: clang-format: [JS] consistenly format enums.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL309703: clang-format: [JS] consistenly format enums. 
(authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36144

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
   return true;
 if (Left.is(tok::l_brace) && Line.Level == 0 &&
 (Line.startsWith(tok::kw_enum) ||
- Line.startsWith(tok::kw_export, tok::kw_enum)))
+ Line.startsWith(tok::kw_const, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum)))
   // JavaScript top-level enum key/value pairs are put on separate lines
   // instead of bin-packing.
   return true;
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1425,6 +1425,14 @@
"  B\n"
"}\n"
"var x = 1;");
+  verifyFormat("const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
+  verifyFormat("export const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
 }
 
 TEST_F(FormatTestJS, MetadataAnnotations) {


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2517,7 +2517,9 @@
   return true;
 if (Left.is(tok::l_brace) && Line.Level == 0 &&
 (Line.startsWith(tok::kw_enum) ||
- Line.startsWith(tok::kw_export, tok::kw_enum)))
+ Line.startsWith(tok::kw_const, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_enum) ||
+ Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum)))
   // JavaScript top-level enum key/value pairs are put on separate lines
   // instead of bin-packing.
   return true;
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1425,6 +1425,14 @@
"  B\n"
"}\n"
"var x = 1;");
+  verifyFormat("const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
+  verifyFormat("export const enum Foo {\n"
+   "  A = 1,\n"
+   "  B\n"
+   "}");
 }
 
 TEST_F(FormatTestJS, MetadataAnnotations) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36147: clang-format: [JS] handle union types in arrow functions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL309707: clang-format: [JS] handle union types in arrow 
functions. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36147

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -533,6 +533,7 @@
 Contexts.back().ContextKind == tok::l_square || // array type
 (Contexts.size() == 1 &&
  Line.MustBeDeclaration)) { // method/property declaration
+  Contexts.back().IsExpression = false;
   Tok->Type = TT_JsTypeColon;
   break;
 }
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -988,6 +988,9 @@
".doSomethingElse(\n"
"// break\n"
");");
+  verifyFormat("const f = (x: string|null): string|null => {\n"
+   "  return x;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReturnStatements) {


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -533,6 +533,7 @@
 Contexts.back().ContextKind == tok::l_square || // array type
 (Contexts.size() == 1 &&
  Line.MustBeDeclaration)) { // method/property declaration
+  Contexts.back().IsExpression = false;
   Tok->Type = TT_JsTypeColon;
   break;
 }
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -988,6 +988,9 @@
".doSomethingElse(\n"
"// break\n"
");");
+  verifyFormat("const f = (x: string|null): string|null => {\n"
+   "  return x;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReturnStatements) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36146: clang-format: [JS] whitespace between keywords and parenthesized expressions.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL309710: clang-format: [JS] whitespace between keywords and 
parenthesized expressions. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36146

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2349,6 +2349,9 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+if (Right.is(tok::l_paren) &&
+Left.isOneOf(tok::kw_throw, Keywords.kw_await, tok::kw_void))
+  return true;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -259,6 +259,15 @@
   "}\n");
 }
 
+TEST_F(FormatTestJS, ReservedWordsParenthesized) {
+  // All of these are statements using the keyword, not function calls.
+  verifyFormat("throw (x + y);\n"
+   "await (await x).y;\n"
+   "void (0);\n"
+   "delete (x.y);\n"
+   "return (x);\n");
+}
+
 TEST_F(FormatTestJS, CppKeywords) {
   // Make sure we don't mess stuff up because of C++ keywords.
   verifyFormat("return operator && (aa);");


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2349,6 +2349,9 @@
 if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
 Left.Tok.getIdentifierInfo())
   return false;
+if (Right.is(tok::l_paren) &&
+Left.isOneOf(tok::kw_throw, Keywords.kw_await, tok::kw_void))
+  return true;
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -259,6 +259,15 @@
   "}\n");
 }
 
+TEST_F(FormatTestJS, ReservedWordsParenthesized) {
+  // All of these are statements using the keyword, not function calls.
+  verifyFormat("throw (x + y);\n"
+   "await (await x).y;\n"
+   "void (0);\n"
+   "delete (x.y);\n"
+   "return (x);\n");
+}
+
 TEST_F(FormatTestJS, CppKeywords) {
   // Make sure we don't mess stuff up because of C++ keywords.
   verifyFormat("return operator && (aa);");
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36139: clang-format: [JS] prefer wrapping chains over empty literals.

2017-08-01 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL309712: clang-format: [JS] prefer wrapping chains over empty 
literals. (authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D36139?vs=109082&id=109155#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D36139

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2006,6 +2006,9 @@
 if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return 100;
+// Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
+if (Left.opensScope() && Right.closesScope())
+  return 200;
   }
 
   if (Right.is(tok::identifier) && Right.Next && 
Right.Next->is(TT_DictLiteral))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -841,6 +841,15 @@
 
 }
 
+TEST_F(FormatTestJS, DontWrapEmptyLiterals) {
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of([]));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of({}));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of(()));");
+}
+
 TEST_F(FormatTestJS, InliningFunctionLiterals) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2006,6 +2006,9 @@
 if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return 100;
+// Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
+if (Left.opensScope() && Right.closesScope())
+  return 200;
   }
 
   if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -841,6 +841,15 @@
 
 }
 
+TEST_F(FormatTestJS, DontWrapEmptyLiterals) {
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of([]));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of({}));");
+  verifyFormat("(a.getData as jasmine.Spy)\n"
+   ".and.returnValue(Observable.of(()));");
+}
+
 TEST_F(FormatTestJS, InliningFunctionLiterals) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36148: clang-format: [JS] support fields with case/switch/default labels.

2017-08-04 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL310070: clang-format: [JS] support fields with 
case/switch/default labels. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36148

Files:
  cfe/trunk/lib/Format/UnwrappedLineParser.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -326,6 +326,11 @@
   break;
 case tok::kw_default:
 case tok::kw_case:
+  if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration) {
+// A 'case: string' style field declaration.
+parseStructuralElement();
+break;
+  }
   if (!SwitchLabelEncountered &&
   (Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 
1)))
 ++Line->Level;
@@ -953,13 +958,22 @@
 parseDoWhile();
 return;
   case tok::kw_switch:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // 'switch: string' field declaration.
+  break;
 parseSwitch();
 return;
   case tok::kw_default:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // 'default: string' field declaration.
+  break;
 nextToken();
 parseLabel();
 return;
   case tok::kw_case:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // 'case: string' field declaration.
+  break;
 parseCaseLabel();
 return;
   case tok::kw_try:
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -242,6 +242,12 @@
   verifyFormat("var interface = 2;");
   verifyFormat("interface = 2;");
   verifyFormat("x = interface instanceof y;");
+  verifyFormat("interface Test {\n"
+   "  x: string;\n"
+   "  switch: string;\n"
+   "  case: string;\n"
+   "  default: string;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReservedWordsMethods) {


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -326,6 +326,11 @@
   break;
 case tok::kw_default:
 case tok::kw_case:
+  if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration) {
+// A 'case: string' style field declaration.
+parseStructuralElement();
+break;
+  }
   if (!SwitchLabelEncountered &&
   (Style.IndentCaseLabels || (Line->InPPDirective && Line->Level == 1)))
 ++Line->Level;
@@ -953,13 +958,22 @@
 parseDoWhile();
 return;
   case tok::kw_switch:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // 'switch: string' field declaration.
+  break;
 parseSwitch();
 return;
   case tok::kw_default:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // 'default: string' field declaration.
+  break;
 nextToken();
 parseLabel();
 return;
   case tok::kw_case:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // 'case: string' field declaration.
+  break;
 parseCaseLabel();
 return;
   case tok::kw_try:
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -242,6 +242,12 @@
   verifyFormat("var interface = 2;");
   verifyFormat("interface = 2;");
   verifyFormat("x = interface instanceof y;");
+  verifyFormat("interface Test {\n"
+   "  x: string;\n"
+   "  switch: string;\n"
+   "  case: string;\n"
+   "  default: string;\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReservedWordsMethods) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36359: [clang-format] Put '/**' and '*/' on own lines in jsdocs ending in comment pragmas

2017-08-07 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: lib/Format/BreakableToken.cpp:688
+  if (DelimitersOnNewline) {
+StringRef TrimmedContent = Content.back().substr(TailOffset).rtrim(Blanks);
+if (!TrimmedContent.empty()) {

Can you add a comment on what this is doing? It's non obvious. Make sure to 
document both intention (why) and implementation (how).



Comment at: lib/Format/BreakableToken.cpp:688
+  if (DelimitersOnNewline) {
+StringRef TrimmedContent = Content.back().substr(TailOffset).rtrim(Blanks);
+if (!TrimmedContent.empty()) {

mprobst wrote:
> Can you add a comment on what this is doing? It's non obvious. Make sure to 
> document both intention (why) and implementation (how).
I don't understand why we're trimming `Content.back()` here, and `Lines.back()` 
below.



Comment at: lib/Format/BreakableToken.cpp:690
+if (!TrimmedContent.empty()) {
+  size_t Whitespaces =
+  Lines.back().size() - Lines.back().rtrim(Blanks).size();

`Whitespaces` seems like a bad variable name, isn't this rather the index of 
trimmed whitespace in the last line?


https://reviews.llvm.org/D36359



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36159: clang-format: [JS] handle single lines comments ending in `\\`.

2017-08-07 Thread Martin Probst via Phabricator via cfe-commits
mprobst added a comment.

Friendly ping.


https://reviews.llvm.org/D36159



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36159: clang-format: [JS] handle single lines comments ending in `\\`.

2017-08-08 Thread Martin Probst via Phabricator via cfe-commits
mprobst marked an inline comment as done.
mprobst added inline comments.



Comment at: lib/Format/FormatTokenLexer.cpp:544-545
+while (BackslashPos != StringRef::npos) {
+  if (BackslashPos + 1 < FormatTok->TokenText.size() &&
+  FormatTok->TokenText[BackslashPos + 1] == '\n') {
+const char *Offset = Lex->getBufferLocation();

klimek wrote:
> Just wondering whether the \n can be in the next token. Probably not, though, 
> the way we set up the lexer.
AFAIU (and experimentation confirms) LLVM always lexes the `\n` as separate 
whitespace from the `// ...` line comment, but for backslash escaped line 
endings after the `\\` the `\n` is inside of it - after all it's part of the 
one comment token that continues on the next line.


https://reviews.llvm.org/D36159



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36159: clang-format: [JS] handle single lines comments ending in `\\`.

2017-08-08 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
mprobst marked 2 inline comments as done.
Closed by commit rL310365: clang-format: [JS] handle single lines comments 
ending in `\\`. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36159

Files:
  cfe/trunk/lib/Format/FormatTokenLexer.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/FormatTokenLexer.cpp
===
--- cfe/trunk/lib/Format/FormatTokenLexer.cpp
+++ cfe/trunk/lib/Format/FormatTokenLexer.cpp
@@ -529,6 +529,34 @@
 readRawToken(*FormatTok);
   }
 
+  // JavaScript and Java do not allow to escape the end of the line with a
+  // backslash. Backslashes are syntax errors in plain source, but can occur in
+  // comments. When a single line comment ends with a \, it'll cause the next
+  // line of code to be lexed as a comment, breaking formatting. The code below
+  // finds comments that contain a backslash followed by a line break, 
truncates
+  // the comment token at the backslash, and resets the lexer to restart behind
+  // the backslash.
+  if ((Style.Language == FormatStyle::LK_JavaScript ||
+   Style.Language == FormatStyle::LK_Java) &&
+  FormatTok->is(tok::comment) && FormatTok->TokenText.startswith("//")) {
+size_t BackslashPos = FormatTok->TokenText.find('\\');
+while (BackslashPos != StringRef::npos) {
+  if (BackslashPos + 1 < FormatTok->TokenText.size() &&
+  FormatTok->TokenText[BackslashPos + 1] == '\n') {
+const char *Offset = Lex->getBufferLocation();
+Offset -= FormatTok->TokenText.size();
+Offset += BackslashPos + 1;
+resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
+FormatTok->TokenText = FormatTok->TokenText.substr(0, BackslashPos + 
1);
+FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
+FormatTok->TokenText, FormatTok->OriginalColumn, Style.TabWidth,
+Encoding);
+break;
+  }
+  BackslashPos = FormatTok->TokenText.find('\\', BackslashPos + 1);
+}
+  }
+
   // In case the token starts with escaped newlines, we want to
   // take them into account as whitespace - this pattern is quite frequent
   // in macro definitions.
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -2074,5 +2074,27 @@
"};", FourSpaces);
 }
 
+TEST_F(FormatTestJS, BackslashesInComments) {
+  verifyFormat("// hello \\\n"
+   "if (x) foo();\n",
+   "// hello \\\n"
+   " if ( x) \n"
+   "   foo();\n");
+  verifyFormat("/* ignore \\\n"
+   " */\n"
+   "if (x) foo();\n",
+   "/* ignore \\\n"
+   " */\n"
+   " if (  x) foo();\n");
+  verifyFormat("// st \\ art\\\n"
+   "// comment"
+   "// continue \\\n"
+   "formatMe();\n",
+   "// st \\ art\\\n"
+   "// comment"
+   "// continue \\\n"
+   "formatMe( );\n");
+}
+
 } // end namespace tooling
 } // end namespace clang


Index: cfe/trunk/lib/Format/FormatTokenLexer.cpp
===
--- cfe/trunk/lib/Format/FormatTokenLexer.cpp
+++ cfe/trunk/lib/Format/FormatTokenLexer.cpp
@@ -529,6 +529,34 @@
 readRawToken(*FormatTok);
   }
 
+  // JavaScript and Java do not allow to escape the end of the line with a
+  // backslash. Backslashes are syntax errors in plain source, but can occur in
+  // comments. When a single line comment ends with a \, it'll cause the next
+  // line of code to be lexed as a comment, breaking formatting. The code below
+  // finds comments that contain a backslash followed by a line break, truncates
+  // the comment token at the backslash, and resets the lexer to restart behind
+  // the backslash.
+  if ((Style.Language == FormatStyle::LK_JavaScript ||
+   Style.Language == FormatStyle::LK_Java) &&
+  FormatTok->is(tok::comment) && FormatTok->TokenText.startswith("//")) {
+size_t BackslashPos = FormatTok->TokenText.find('\\');
+while (BackslashPos != StringRef::npos) {
+  if (BackslashPos + 1 < FormatTok->TokenText.size() &&
+  FormatTok->TokenText[BackslashPos + 1] == '\n') {
+const char *Offset = Lex->getBufferLocation();
+Offset -= FormatTok->TokenText.size();
+Offset += BackslashPos + 1;
+resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
+FormatTok->TokenText = FormatTok->TokenText.substr(0, BackslashPos + 1);
+FormatTok->ColumnWidth = encoding::columnWidthWithTabs(
+FormatTok->TokenText, FormatTok->OriginalColumn, Style.TabWidth,
+Encoding);
+break;
+   

[PATCH] D36491: clang-format: [JS] detect ASI after closing parens.

2017-08-08 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

A closing parenthesis followed by a declaration or statement should always 
terminate the current statement.


https://reviews.llvm.org/D36491

Files:
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1059,6 +1059,10 @@
"  readonly ratherLongField = 1;\n"
"}",
getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = (5 + 9)\n"
+   "const y = 3\n",
+   "const x = (   5 +9)\n"
+   "const y = 3\n");
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -853,7 +853,8 @@
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
  tok::minusminus)))
 return addUnwrappedLine();
-  if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
+  if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
+  isJSDeclOrStmt(Keywords, Next))
 return addUnwrappedLine();
 }
 


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1059,6 +1059,10 @@
"  readonly ratherLongField = 1;\n"
"}",
getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = (5 + 9)\n"
+   "const y = 3\n",
+   "const x = (   5 +9)\n"
+   "const y = 3\n");
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
Index: lib/Format/UnwrappedLineParser.cpp
===
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -853,7 +853,8 @@
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
  tok::minusminus)))
 return addUnwrappedLine();
-  if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
+  if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
+  isJSDeclOrStmt(Keywords, Next))
 return addUnwrappedLine();
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36491: clang-format: [JS] detect ASI after closing parens.

2017-08-09 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL310482: clang-format: [JS] detect ASI after closing parens. 
(authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36491

Files:
  cfe/trunk/lib/Format/UnwrappedLineParser.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -853,7 +853,8 @@
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
  tok::minusminus)))
 return addUnwrappedLine();
-  if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
+  if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
+  isJSDeclOrStmt(Keywords, Next))
 return addUnwrappedLine();
 }
 
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1106,6 +1106,10 @@
"  readonly ratherLongField = 1;\n"
"}",
getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = (5 + 9)\n"
+   "const y = 3\n",
+   "const x = (   5 +9)\n"
+   "const y = 3\n");
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {


Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
===
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp
@@ -853,7 +853,8 @@
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
  tok::minusminus)))
 return addUnwrappedLine();
-  if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
+  if ((PreviousMustBeValue || Previous->is(tok::r_paren)) &&
+  isJSDeclOrStmt(Keywords, Next))
 return addUnwrappedLine();
 }
 
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1106,6 +1106,10 @@
"  readonly ratherLongField = 1;\n"
"}",
getGoogleJSStyleWithColumns(20));
+  verifyFormat("const x = (5 + 9)\n"
+   "const y = 3\n",
+   "const x = (   5 +9)\n"
+   "const y = 3\n");
 }
 
 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36142: clang-format: [JS] do not insert whitespace in call positions.

2017-08-14 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 110959.
mprobst marked 2 inline comments as done.
mprobst added a comment.

- clean up implementation, just use getIdentifierInfo
- clean up tests, remove illegal syntax, add more tests


https://reviews.llvm.org/D36142

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -271,14 +271,21 @@
   verifyFormat("x.case = 1;");
   verifyFormat("x.interface = 1;");
   verifyFormat("x.for = 1;");
-  verifyFormat("x.of() = 1;");
+  verifyFormat("x.of();");
   verifyFormat("of(null);");
   verifyFormat("import {of} from 'x';");
-  verifyFormat("x.in() = 1;");
-  verifyFormat("x.let() = 1;");
-  verifyFormat("x.var() = 1;");
-  verifyFormat("x.for() = 1;");
-  verifyFormat("x.as() = 1;");
+  verifyFormat("x.in();");
+  verifyFormat("x.let();");
+  verifyFormat("x.var();");
+  verifyFormat("x.for();");
+  verifyFormat("x.as();");
+  verifyFormat("x.instanceof();");
+  verifyFormat("x.switch();");
+  verifyFormat("x.case();");
+  verifyFormat("x.delete();");
+  verifyFormat("x.throw();");
+  verifyFormat("x.throws();");
+  verifyFormat("x.if();");
   verifyFormat("x = {\n"
"  a: 12,\n"
"  interface: 1,\n"
@@ -1228,7 +1235,6 @@
   // But, of course, "catch" is a perfectly fine function name in JavaScript.
   verifyFormat("someObject.catch();");
   verifyFormat("someObject.new();");
-  verifyFormat("someObject.delete();");
 }
 
 TEST_F(FormatTestJS, StringLiteralConcatenation) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2367,13 +2367,20 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
  Keywords.kw_extends, Keywords.kw_implements))
   return true;
-// JS methods can use some keywords as names (e.g. `delete()`).
-if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
-Left.Tok.getIdentifierInfo())
-  return false;
-if (Right.is(tok::l_paren) &&
-Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof, 
tok::kw_void))
-  return true;
+if (Right.is(tok::l_paren)) {
+  // JS methods can use some keywords as names (e.g. `delete()`).
+  if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo())
+return false;
+  // Valid JS method names can include keywords, e.g. `foo.delete()` or
+  // `bar.instanceof()`. Recognize call positions by preceding period.
+  if (Left.Previous && Left.Previous->is(tok::period) &&
+  Left.Tok.getIdentifierInfo())
+return false;
+  // Additional unary JavaScript operators that need a space after.
+  if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof,
+   tok::kw_void))
+return true;
+}
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -271,14 +271,21 @@
   verifyFormat("x.case = 1;");
   verifyFormat("x.interface = 1;");
   verifyFormat("x.for = 1;");
-  verifyFormat("x.of() = 1;");
+  verifyFormat("x.of();");
   verifyFormat("of(null);");
   verifyFormat("import {of} from 'x';");
-  verifyFormat("x.in() = 1;");
-  verifyFormat("x.let() = 1;");
-  verifyFormat("x.var() = 1;");
-  verifyFormat("x.for() = 1;");
-  verifyFormat("x.as() = 1;");
+  verifyFormat("x.in();");
+  verifyFormat("x.let();");
+  verifyFormat("x.var();");
+  verifyFormat("x.for();");
+  verifyFormat("x.as();");
+  verifyFormat("x.instanceof();");
+  verifyFormat("x.switch();");
+  verifyFormat("x.case();");
+  verifyFormat("x.delete();");
+  verifyFormat("x.throw();");
+  verifyFormat("x.throws();");
+  verifyFormat("x.if();");
   verifyFormat("x = {\n"
"  a: 12,\n"
"  interface: 1,\n"
@@ -1228,7 +1235,6 @@
   // But, of course, "catch" is a perfectly fine function name in JavaScript.
   verifyFormat("someObject.catch();");
   verifyFormat("someObject.new();");
-  verifyFormat("someObject.delete();");
 }
 
 TEST_F(FormatTestJS, StringLiteralConcatenation) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -2367,13 +2367,20 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
  Keywords.kw_extends, Keywords.kw_implements))
   return true;
-// JS methods can use some keywords as names (e.g. `delete()`).
-if 

[PATCH] D36142: clang-format: [JS] do not insert whitespace in call positions.

2017-08-14 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: lib/Format/TokenAnnotator.cpp:2355
+(Left.Tok.getIdentifierInfo() ||
+ Left.isOneOf(tok::kw_switch, tok::kw_case, tok::kw_delete)))
+  return false;

djasper wrote:
> Why is instanceof not required in this list?
`instanceof` is not a keyword in the C++ sense, so it is covered by the 
`getIdentifierInfo` part. But this was actually a misunderstanding - 
`getIdentifierInfo` actually covers all keyword-ish tokens, so we don't need 
the list of tokens here at all.


https://reviews.llvm.org/D36142



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36684: clang-format: [JS] wrap optional properties in type aliases.

2017-08-14 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
Herald added a subscriber: klimek.

clang-format wraps object literal keys in an object literal if they are
marked as `TT_SelectorName`s and/or the colon is marked as
`TT_DictLiteral`. Previously, clang-format would accidentally work
because colons in type aliases were marked as `TT_DictLiteral`. r310367
fixed this to assing `TT_JsTypeColon`, which broke wrapping in certain
situations. However the root cause was that clang-format incorrectly
didn't skip questionmarks when detecting selector name.

This change fixes both locations to (1) assign `TT_SelectorName` and (2)
treat `TT_JsTypeColon` like `TT_DictLiteral`.

Previously:

  type X = {
a: string, b?: string,
  };

Now:

  type X = {
a: string,
b?: string,
  };


https://reviews.llvm.org/D36684

Files:
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTestJS.cpp


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1555,6 +1555,10 @@
"  y: number\n"
"};\n"
"class C {}");
+  verifyFormat("export type X = {\n"
+   "  a: string,\n"
+   "  b?: string,\n"
+   "};\n");
 }
 
 TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -459,6 +459,8 @@
 updateParameterCount(Left, CurrentToken);
 if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
   FormatToken *Previous = CurrentToken->getPreviousNonComment();
+  if (Previous->is(TT_JsTypeOptionalQuestion))
+Previous = Previous->getPreviousNonComment();
   if (((CurrentToken->is(tok::colon) &&
 (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
Style.Language == FormatStyle::LK_Proto ||
@@ -1601,7 +1603,7 @@
   if (Current->is(TT_ConditionalExpr))
 return prec::Conditional;
   if (NextNonComment && Current->is(TT_SelectorName) &&
-  (NextNonComment->is(TT_DictLiteral) ||
+  (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) ||
((Style.Language == FormatStyle::LK_Proto ||
  Style.Language == FormatStyle::LK_TextProto) &&
 NextNonComment->is(tok::less


Index: unittests/Format/FormatTestJS.cpp
===
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -1555,6 +1555,10 @@
"  y: number\n"
"};\n"
"class C {}");
+  verifyFormat("export type X = {\n"
+   "  a: string,\n"
+   "  b?: string,\n"
+   "};\n");
 }
 
 TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
Index: lib/Format/TokenAnnotator.cpp
===
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -459,6 +459,8 @@
 updateParameterCount(Left, CurrentToken);
 if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
   FormatToken *Previous = CurrentToken->getPreviousNonComment();
+  if (Previous->is(TT_JsTypeOptionalQuestion))
+Previous = Previous->getPreviousNonComment();
   if (((CurrentToken->is(tok::colon) &&
 (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
Style.Language == FormatStyle::LK_Proto ||
@@ -1601,7 +1603,7 @@
   if (Current->is(TT_ConditionalExpr))
 return prec::Conditional;
   if (NextNonComment && Current->is(TT_SelectorName) &&
-  (NextNonComment->is(TT_DictLiteral) ||
+  (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) ||
((Style.Language == FormatStyle::LK_Proto ||
  Style.Language == FormatStyle::LK_TextProto) &&
 NextNonComment->is(tok::less
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36142: clang-format: [JS] do not insert whitespace in call positions.

2017-08-14 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL310851: clang-format: [JS] do not insert whitespace in call 
positions. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36142

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2367,13 +2367,20 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
  Keywords.kw_extends, Keywords.kw_implements))
   return true;
-// JS methods can use some keywords as names (e.g. `delete()`).
-if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
-Left.Tok.getIdentifierInfo())
-  return false;
-if (Right.is(tok::l_paren) &&
-Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof, 
tok::kw_void))
-  return true;
+if (Right.is(tok::l_paren)) {
+  // JS methods can use some keywords as names (e.g. `delete()`).
+  if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo())
+return false;
+  // Valid JS method names can include keywords, e.g. `foo.delete()` or
+  // `bar.instanceof()`. Recognize call positions by preceding period.
+  if (Left.Previous && Left.Previous->is(tok::period) &&
+  Left.Tok.getIdentifierInfo())
+return false;
+  // Additional unary JavaScript operators that need a space after.
+  if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof,
+   tok::kw_void))
+return true;
+}
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -271,14 +271,21 @@
   verifyFormat("x.case = 1;");
   verifyFormat("x.interface = 1;");
   verifyFormat("x.for = 1;");
-  verifyFormat("x.of() = 1;");
+  verifyFormat("x.of();");
   verifyFormat("of(null);");
   verifyFormat("import {of} from 'x';");
-  verifyFormat("x.in() = 1;");
-  verifyFormat("x.let() = 1;");
-  verifyFormat("x.var() = 1;");
-  verifyFormat("x.for() = 1;");
-  verifyFormat("x.as() = 1;");
+  verifyFormat("x.in();");
+  verifyFormat("x.let();");
+  verifyFormat("x.var();");
+  verifyFormat("x.for();");
+  verifyFormat("x.as();");
+  verifyFormat("x.instanceof();");
+  verifyFormat("x.switch();");
+  verifyFormat("x.case();");
+  verifyFormat("x.delete();");
+  verifyFormat("x.throw();");
+  verifyFormat("x.throws();");
+  verifyFormat("x.if();");
   verifyFormat("x = {\n"
"  a: 12,\n"
"  interface: 1,\n"
@@ -1228,7 +1235,6 @@
   // But, of course, "catch" is a perfectly fine function name in JavaScript.
   verifyFormat("someObject.catch();");
   verifyFormat("someObject.new();");
-  verifyFormat("someObject.delete();");
 }
 
 TEST_F(FormatTestJS, StringLiteralConcatenation) {


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -2367,13 +2367,20 @@
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
  Keywords.kw_extends, Keywords.kw_implements))
   return true;
-// JS methods can use some keywords as names (e.g. `delete()`).
-if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
-Left.Tok.getIdentifierInfo())
-  return false;
-if (Right.is(tok::l_paren) &&
-Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof, tok::kw_void))
-  return true;
+if (Right.is(tok::l_paren)) {
+  // JS methods can use some keywords as names (e.g. `delete()`).
+  if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo())
+return false;
+  // Valid JS method names can include keywords, e.g. `foo.delete()` or
+  // `bar.instanceof()`. Recognize call positions by preceding period.
+  if (Left.Previous && Left.Previous->is(tok::period) &&
+  Left.Tok.getIdentifierInfo())
+return false;
+  // Additional unary JavaScript operators that need a space after.
+  if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof,
+   tok::kw_void))
+return true;
+}
 if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
   tok::kw_const) ||
  // "of" is only a keyword if it appears after another identifier
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
=

[PATCH] D36684: clang-format: [JS] wrap optional properties in type aliases.

2017-08-14 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL310852: clang-format: [JS] wrap optional properties in type 
aliases. (authored by mprobst).

Repository:
  rL LLVM

https://reviews.llvm.org/D36684

Files:
  cfe/trunk/lib/Format/TokenAnnotator.cpp
  cfe/trunk/unittests/Format/FormatTestJS.cpp


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -459,6 +459,8 @@
 updateParameterCount(Left, CurrentToken);
 if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
   FormatToken *Previous = CurrentToken->getPreviousNonComment();
+  if (Previous->is(TT_JsTypeOptionalQuestion))
+Previous = Previous->getPreviousNonComment();
   if (((CurrentToken->is(tok::colon) &&
 (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
Style.Language == FormatStyle::LK_Proto ||
@@ -1601,7 +1603,7 @@
   if (Current->is(TT_ConditionalExpr))
 return prec::Conditional;
   if (NextNonComment && Current->is(TT_SelectorName) &&
-  (NextNonComment->is(TT_DictLiteral) ||
+  (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) ||
((Style.Language == FormatStyle::LK_Proto ||
  Style.Language == FormatStyle::LK_TextProto) &&
 NextNonComment->is(tok::less
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1561,6 +1561,10 @@
"  y: number\n"
"};\n"
"class C {}");
+  verifyFormat("export type X = {\n"
+   "  a: string,\n"
+   "  b?: string,\n"
+   "};\n");
 }
 
 TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {


Index: cfe/trunk/lib/Format/TokenAnnotator.cpp
===
--- cfe/trunk/lib/Format/TokenAnnotator.cpp
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp
@@ -459,6 +459,8 @@
 updateParameterCount(Left, CurrentToken);
 if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
   FormatToken *Previous = CurrentToken->getPreviousNonComment();
+  if (Previous->is(TT_JsTypeOptionalQuestion))
+Previous = Previous->getPreviousNonComment();
   if (((CurrentToken->is(tok::colon) &&
 (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
Style.Language == FormatStyle::LK_Proto ||
@@ -1601,7 +1603,7 @@
   if (Current->is(TT_ConditionalExpr))
 return prec::Conditional;
   if (NextNonComment && Current->is(TT_SelectorName) &&
-  (NextNonComment->is(TT_DictLiteral) ||
+  (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) ||
((Style.Language == FormatStyle::LK_Proto ||
  Style.Language == FormatStyle::LK_TextProto) &&
 NextNonComment->is(tok::less
Index: cfe/trunk/unittests/Format/FormatTestJS.cpp
===
--- cfe/trunk/unittests/Format/FormatTestJS.cpp
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp
@@ -1561,6 +1561,10 @@
"  y: number\n"
"};\n"
"class C {}");
+  verifyFormat("export type X = {\n"
+   "  a: string,\n"
+   "  b?: string,\n"
+   "};\n");
 }
 
 TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D70377: clang-format: [JS] tests for async wrapping.

2020-01-16 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG736a3802124b: clang-format: [JS] tests for async wrapping. 
(authored by mprobst).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D70377/new/

https://reviews.llvm.org/D70377

Files:
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -737,6 +737,22 @@
"   function a() {\n"
"  return   1;\n"
"}  \n");
+  // clang-format must not insert breaks between async and function, otherwise
+  // automatic semicolon insertion may trigger (in particular in a class body).
+  verifyFormat("async function\n"
+   "hello(\n"
+   "myparamnameiswaytoolng) {\n"
+   "}",
+   "async function hello(myparamnameiswaytoolng) {}",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("class C {\n"
+   "  async hello(\n"
+   "  myparamnameiswaytoolng) {\n"
+   "  }\n"
+   "}",
+   "class C {\n"
+   "  async hello(myparamnameiswaytoolng) {} }",
+   getGoogleJSStyleWithColumns(10));
   verifyFormat("async function* f() {\n"
"  yield fetch(x);\n"
"}");


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -737,6 +737,22 @@
"   function a() {\n"
"  return   1;\n"
"}  \n");
+  // clang-format must not insert breaks between async and function, otherwise
+  // automatic semicolon insertion may trigger (in particular in a class body).
+  verifyFormat("async function\n"
+   "hello(\n"
+   "myparamnameiswaytoolng) {\n"
+   "}",
+   "async function hello(myparamnameiswaytoolng) {}",
+   getGoogleJSStyleWithColumns(10));
+  verifyFormat("class C {\n"
+   "  async hello(\n"
+   "  myparamnameiswaytoolng) {\n"
+   "  }\n"
+   "}",
+   "class C {\n"
+   "  async hello(myparamnameiswaytoolng) {} }",
+   getGoogleJSStyleWithColumns(10));
   verifyFormat("async function* f() {\n"
"  yield fetch(x);\n"
"}");
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72827: clang-format: [JS] Handle keyword-named methods.

2020-01-16 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
Herald added a project: clang.

Including `do`, `for`, and `while`, in addition to the previously
handled fields. The unit test explicitly uses methods, but this code
path handles both fields and methods.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72827

Files:
  clang/lib/Format/UnwrappedLineParser.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -343,6 +343,14 @@
"  x: 'x'\n"
"};",
"const Axis = {for: 'for', x:   'x'};");
+  verifyFormat("class KeywordNamedMethods {\n"
+   "  do() {\n"
+   "  }\n"
+   "  for() {\n"
+   "  }\n"
+   "  while() {\n"
+   "  }\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReservedWordsMethods) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1015,9 +1015,15 @@
 return;
   case tok::kw_for:
   case tok::kw_while:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // field/method declaration.
+  break;
 parseForOrWhileLoop();
 return;
   case tok::kw_do:
+if (Style.Language == FormatStyle::LK_JavaScript && 
Line->MustBeDeclaration)
+  // field/method declaration.
+  break;
 parseDoWhile();
 return;
   case tok::kw_switch:


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -343,6 +343,14 @@
"  x: 'x'\n"
"};",
"const Axis = {for: 'for', x:   'x'};");
+  verifyFormat("class KeywordNamedMethods {\n"
+   "  do() {\n"
+   "  }\n"
+   "  for() {\n"
+   "  }\n"
+   "  while() {\n"
+   "  }\n"
+   "}\n");
 }
 
 TEST_F(FormatTestJS, ReservedWordsMethods) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1015,9 +1015,15 @@
 return;
   case tok::kw_for:
   case tok::kw_while:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // field/method declaration.
+  break;
 parseForOrWhileLoop();
 return;
   case tok::kw_do:
+if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration)
+  // field/method declaration.
+  break;
 parseDoWhile();
 return;
   case tok::kw_switch:
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D91078: [clang-format] do not break before @tags in JS comments

2020-11-09 Thread Martin Probst via Phabricator via cfe-commits
mprobst added a comment.

See my comment on the upstream bug, let's chat a bit about whether we need this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D91078/new/

https://reviews.llvm.org/D91078

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D91132: clang-format: [JS] support new assignment operators.

2020-11-10 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
Herald added a project: clang.
mprobst requested review of this revision.

Before:

  a && = b;

After:

  a &&= b;

These operators are new additions in ES2021.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D91132

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/FormatTokenLexer.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2424,6 +2424,15 @@
   getGoogleJSStyleWithColumns(40));
 }
 
+TEST_F(FormatTestJS, AssignmentOperators) {
+  verifyFormat("a &&= b;\n");
+  verifyFormat("a ||= b;\n");
+  // NB: need to split ? ?= to avoid it being interpreted by C++ as a trigraph
+  // for #.
+  verifyFormat("a ?"
+   "?= b;\n");
+}
+
 TEST_F(FormatTestJS, Conditional) {
   verifyFormat("y = x ? 1 : 2;");
   verifyFormat("x ? 1 : 2;");
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -121,6 +121,10 @@
tok::period};
 static const tok::TokenKind JSNullishOperator[] = {tok::question,
tok::question};
+static const tok::TokenKind JSNullishEqual[] = {tok::question,
+tok::question, tok::equal};
+static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, 
tok::equal};
+static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
 
 // FIXME: Investigate what token type gives the correct operator priority.
 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -148,6 +152,13 @@
   Tokens.back()->Tok.setKind(tok::period);
   return;
 }
+if (tryMergeTokens(JSAndAndEqual, TT_JsAndAndEqual) ||
+tryMergeTokens(JSPipePipeEqual, TT_JsPipePipeEqual) ||
+tryMergeTokens(JSNullishEqual, TT_JsNullishCoalescingEqual)) {
+  // Treat like the "||" operator (as opposed to the ternary ?).
+  Tokens.back()->Tok.setKind(tok::equal);
+  return;
+}
 if (tryMergeJSPrivateIdentifier())
   return;
   }
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -68,6 +68,9 @@
   TYPE(JsTypeColon)
\
   TYPE(JsTypeOperator) 
\
   TYPE(JsTypeOptionalQuestion) 
\
+  TYPE(JsAndAndEqual)  
\
+  TYPE(JsPipePipeEqual)
\
+  TYPE(JsNullishCoalescingEqual)   
\
   TYPE(LambdaArrow)
\
   TYPE(LambdaLBrace)   
\
   TYPE(LambdaLSquare)  
\


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2424,6 +2424,15 @@
   getGoogleJSStyleWithColumns(40));
 }
 
+TEST_F(FormatTestJS, AssignmentOperators) {
+  verifyFormat("a &&= b;\n");
+  verifyFormat("a ||= b;\n");
+  // NB: need to split ? ?= to avoid it being interpreted by C++ as a trigraph
+  // for #.
+  verifyFormat("a ?"
+   "?= b;\n");
+}
+
 TEST_F(FormatTestJS, Conditional) {
   verifyFormat("y = x ? 1 : 2;");
   verifyFormat("x ? 1 : 2;");
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -121,6 +121,10 @@
tok::period};
 static const tok::TokenKind JSNullishOperator[] = {tok::question,
tok::question};
+static const tok::TokenKind JSNullishEqual[] = {tok::question,
+tok::question, tok::equal};
+static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, tok::equal};
+static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
 
 // FIXME: Investigate what token type gives the correct operator priority.
 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -148,6 +152,13 @@
   Tokens.back()->Tok.setKind(tok::period);
   return;
 }
+if (tryMergeTo

[PATCH] D91132: clang-format: [JS] support new assignment operators.

2020-11-10 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 304069.
mprobst added a comment.

- fix comment


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D91132/new/

https://reviews.llvm.org/D91132

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/FormatTokenLexer.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2424,6 +2424,15 @@
   getGoogleJSStyleWithColumns(40));
 }
 
+TEST_F(FormatTestJS, AssignmentOperators) {
+  verifyFormat("a &&= b;\n");
+  verifyFormat("a ||= b;\n");
+  // NB: need to split ? ?= to avoid it being interpreted by C++ as a trigraph
+  // for #.
+  verifyFormat("a ?"
+   "?= b;\n");
+}
+
 TEST_F(FormatTestJS, Conditional) {
   verifyFormat("y = x ? 1 : 2;");
   verifyFormat("x ? 1 : 2;");
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -121,6 +121,10 @@
tok::period};
 static const tok::TokenKind JSNullishOperator[] = {tok::question,
tok::question};
+static const tok::TokenKind JSNullishEqual[] = {tok::question,
+tok::question, tok::equal};
+static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, 
tok::equal};
+static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
 
 // FIXME: Investigate what token type gives the correct operator priority.
 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -148,6 +152,13 @@
   Tokens.back()->Tok.setKind(tok::period);
   return;
 }
+if (tryMergeTokens(JSAndAndEqual, TT_JsAndAndEqual) ||
+tryMergeTokens(JSPipePipeEqual, TT_JsPipePipeEqual) ||
+tryMergeTokens(JSNullishEqual, TT_JsNullishCoalescingEqual)) {
+  // Treat like the "=" assignment operator.
+  Tokens.back()->Tok.setKind(tok::equal);
+  return;
+}
 if (tryMergeJSPrivateIdentifier())
   return;
   }
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -68,6 +68,9 @@
   TYPE(JsTypeColon)
\
   TYPE(JsTypeOperator) 
\
   TYPE(JsTypeOptionalQuestion) 
\
+  TYPE(JsAndAndEqual)  
\
+  TYPE(JsPipePipeEqual)
\
+  TYPE(JsNullishCoalescingEqual)   
\
   TYPE(LambdaArrow)
\
   TYPE(LambdaLBrace)   
\
   TYPE(LambdaLSquare)  
\


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2424,6 +2424,15 @@
   getGoogleJSStyleWithColumns(40));
 }
 
+TEST_F(FormatTestJS, AssignmentOperators) {
+  verifyFormat("a &&= b;\n");
+  verifyFormat("a ||= b;\n");
+  // NB: need to split ? ?= to avoid it being interpreted by C++ as a trigraph
+  // for #.
+  verifyFormat("a ?"
+   "?= b;\n");
+}
+
 TEST_F(FormatTestJS, Conditional) {
   verifyFormat("y = x ? 1 : 2;");
   verifyFormat("x ? 1 : 2;");
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -121,6 +121,10 @@
tok::period};
 static const tok::TokenKind JSNullishOperator[] = {tok::question,
tok::question};
+static const tok::TokenKind JSNullishEqual[] = {tok::question,
+tok::question, tok::equal};
+static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, tok::equal};
+static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
 
 // FIXME: Investigate what token type gives the correct operator priority.
 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -148,6 +152,13 @@
   Tokens.back()->Tok.setKind(tok::period);
   return;
 }
+if (tryMergeTokens(JSAndAndEqual, TT_JsAndAndEqual) ||
+tryMergeTokens(JSPipePipeEqual, TT_JsPipePipeEq

[PATCH] D91132: clang-format: [JS] support new assignment operators.

2020-11-10 Thread Martin Probst via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG16212b8b3e4f: clang-format: [JS] support new assignment 
operators. (authored by mprobst).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D91132/new/

https://reviews.llvm.org/D91132

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/FormatTokenLexer.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2424,6 +2424,15 @@
   getGoogleJSStyleWithColumns(40));
 }
 
+TEST_F(FormatTestJS, AssignmentOperators) {
+  verifyFormat("a &&= b;\n");
+  verifyFormat("a ||= b;\n");
+  // NB: need to split ? ?= to avoid it being interpreted by C++ as a trigraph
+  // for #.
+  verifyFormat("a ?"
+   "?= b;\n");
+}
+
 TEST_F(FormatTestJS, Conditional) {
   verifyFormat("y = x ? 1 : 2;");
   verifyFormat("x ? 1 : 2;");
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -121,6 +121,10 @@
tok::period};
 static const tok::TokenKind JSNullishOperator[] = {tok::question,
tok::question};
+static const tok::TokenKind JSNullishEqual[] = {tok::question,
+tok::question, tok::equal};
+static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, 
tok::equal};
+static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
 
 // FIXME: Investigate what token type gives the correct operator priority.
 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -148,6 +152,13 @@
   Tokens.back()->Tok.setKind(tok::period);
   return;
 }
+if (tryMergeTokens(JSAndAndEqual, TT_JsAndAndEqual) ||
+tryMergeTokens(JSPipePipeEqual, TT_JsPipePipeEqual) ||
+tryMergeTokens(JSNullishEqual, TT_JsNullishCoalescingEqual)) {
+  // Treat like the "=" assignment operator.
+  Tokens.back()->Tok.setKind(tok::equal);
+  return;
+}
 if (tryMergeJSPrivateIdentifier())
   return;
   }
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -68,6 +68,9 @@
   TYPE(JsTypeColon)
\
   TYPE(JsTypeOperator) 
\
   TYPE(JsTypeOptionalQuestion) 
\
+  TYPE(JsAndAndEqual)  
\
+  TYPE(JsPipePipeEqual)
\
+  TYPE(JsNullishCoalescingEqual)   
\
   TYPE(LambdaArrow)
\
   TYPE(LambdaLBrace)   
\
   TYPE(LambdaLSquare)  
\


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2424,6 +2424,15 @@
   getGoogleJSStyleWithColumns(40));
 }
 
+TEST_F(FormatTestJS, AssignmentOperators) {
+  verifyFormat("a &&= b;\n");
+  verifyFormat("a ||= b;\n");
+  // NB: need to split ? ?= to avoid it being interpreted by C++ as a trigraph
+  // for #.
+  verifyFormat("a ?"
+   "?= b;\n");
+}
+
 TEST_F(FormatTestJS, Conditional) {
   verifyFormat("y = x ? 1 : 2;");
   verifyFormat("x ? 1 : 2;");
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -121,6 +121,10 @@
tok::period};
 static const tok::TokenKind JSNullishOperator[] = {tok::question,
tok::question};
+static const tok::TokenKind JSNullishEqual[] = {tok::question,
+tok::question, tok::equal};
+static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, tok::equal};
+static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal};
 
 // FIXME: Investigate what token type gives the correct operator priority.
 if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -148,6 +152,13 @@
   Tokens.back()->Tok.setKind

[PATCH] D91078: [clang-format] do not break before @tags in JS comments

2020-11-10 Thread Martin Probst via Phabricator via cfe-commits
mprobst added a comment.

For posterity: there was a question whether this is legal syntax in JSDoc in 
the first place (e.g. whether it should be escaped). That remains unclear - 
Closure Compiler parser however does ignore JSDoc tags if the line does not 
start with an `@` tag. So the safe thing is to do what this revision does, 
avoid wrapping.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D91078/new/

https://reviews.llvm.org/D91078

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D104101: clang-format: [JS] don't sort named imports if off.

2021-06-11 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
mprobst requested review of this revision.
Herald added a project: clang.

The previous implementation would accidentally still sort the individual
named imports, even if the module reference was in a clang-format off
block.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D104101

Files:
  clang/lib/Format/SortJavaScriptImports.cpp
  clang/unittests/Format/SortImportsTestJS.cpp


Index: clang/unittests/Format/SortImportsTestJS.cpp
===
--- clang/unittests/Format/SortImportsTestJS.cpp
+++ clang/unittests/Format/SortImportsTestJS.cpp
@@ -431,6 +431,17 @@
  "// clang-format off\n");
 }
 
+TEST_F(SortImportsTestJS, RespectsClangFormatOffInNamedImports) {
+  verifySort("// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x = 1;",
+ "// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x =   1;");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: clang/lib/Format/SortJavaScriptImports.cpp
===
--- clang/lib/Format/SortJavaScriptImports.cpp
+++ clang/lib/Format/SortJavaScriptImports.cpp
@@ -317,6 +317,11 @@
 
   // Appends ``Reference`` to ``Buffer``.
   void appendReference(std::string &Buffer, JsModuleReference &Reference) {
+if (Reference.FormattingOff) {
+  Buffer +=
+  getSourceText(Reference.Range.getBegin(), Reference.Range.getEnd());
+  return;
+}
 // Sort the individual symbols within the import.
 // E.g. `import {b, a} from 'x';` -> `import {a, b} from 'x';`
 SmallVector Symbols = Reference.Symbols;


Index: clang/unittests/Format/SortImportsTestJS.cpp
===
--- clang/unittests/Format/SortImportsTestJS.cpp
+++ clang/unittests/Format/SortImportsTestJS.cpp
@@ -431,6 +431,17 @@
  "// clang-format off\n");
 }
 
+TEST_F(SortImportsTestJS, RespectsClangFormatOffInNamedImports) {
+  verifySort("// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x = 1;",
+ "// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x =   1;");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: clang/lib/Format/SortJavaScriptImports.cpp
===
--- clang/lib/Format/SortJavaScriptImports.cpp
+++ clang/lib/Format/SortJavaScriptImports.cpp
@@ -317,6 +317,11 @@
 
   // Appends ``Reference`` to ``Buffer``.
   void appendReference(std::string &Buffer, JsModuleReference &Reference) {
+if (Reference.FormattingOff) {
+  Buffer +=
+  getSourceText(Reference.Range.getBegin(), Reference.Range.getEnd());
+  return;
+}
 // Sort the individual symbols within the import.
 // E.g. `import {b, a} from 'x';` -> `import {a, b} from 'x';`
 SmallVector Symbols = Reference.Symbols;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D104101: clang-format: [JS] don't sort named imports if off.

2021-06-11 Thread Martin Probst via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG63042d46bb0c: clang-format: [JS] don't sort named 
imports if off. (authored by mprobst).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D104101/new/

https://reviews.llvm.org/D104101

Files:
  clang/lib/Format/SortJavaScriptImports.cpp
  clang/unittests/Format/SortImportsTestJS.cpp


Index: clang/unittests/Format/SortImportsTestJS.cpp
===
--- clang/unittests/Format/SortImportsTestJS.cpp
+++ clang/unittests/Format/SortImportsTestJS.cpp
@@ -431,6 +431,17 @@
  "// clang-format off\n");
 }
 
+TEST_F(SortImportsTestJS, RespectsClangFormatOffInNamedImports) {
+  verifySort("// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x = 1;",
+ "// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x =   1;");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: clang/lib/Format/SortJavaScriptImports.cpp
===
--- clang/lib/Format/SortJavaScriptImports.cpp
+++ clang/lib/Format/SortJavaScriptImports.cpp
@@ -317,6 +317,11 @@
 
   // Appends ``Reference`` to ``Buffer``.
   void appendReference(std::string &Buffer, JsModuleReference &Reference) {
+if (Reference.FormattingOff) {
+  Buffer +=
+  getSourceText(Reference.Range.getBegin(), Reference.Range.getEnd());
+  return;
+}
 // Sort the individual symbols within the import.
 // E.g. `import {b, a} from 'x';` -> `import {a, b} from 'x';`
 SmallVector Symbols = Reference.Symbols;


Index: clang/unittests/Format/SortImportsTestJS.cpp
===
--- clang/unittests/Format/SortImportsTestJS.cpp
+++ clang/unittests/Format/SortImportsTestJS.cpp
@@ -431,6 +431,17 @@
  "// clang-format off\n");
 }
 
+TEST_F(SortImportsTestJS, RespectsClangFormatOffInNamedImports) {
+  verifySort("// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x = 1;",
+ "// clang-format off\n"
+ "import {B, A} from './b';\n"
+ "// clang-format on\n"
+ "const x =   1;");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: clang/lib/Format/SortJavaScriptImports.cpp
===
--- clang/lib/Format/SortJavaScriptImports.cpp
+++ clang/lib/Format/SortJavaScriptImports.cpp
@@ -317,6 +317,11 @@
 
   // Appends ``Reference`` to ``Buffer``.
   void appendReference(std::string &Buffer, JsModuleReference &Reference) {
+if (Reference.FormattingOff) {
+  Buffer +=
+  getSourceText(Reference.Range.getBegin(), Reference.Range.getEnd());
+  return;
+}
 // Sort the individual symbols within the import.
 // E.g. `import {b, a} from 'x';` -> `import {a, b} from 'x';`
 SmallVector Symbols = Reference.Symbols;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105087: [clang-format] PR49960 clang-format doesn't handle ASI after "return" on JavaScript

2021-06-29 Thread Martin Probst via Phabricator via cfe-commits
mprobst added inline comments.



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:1015
+if (!eof()) {
+  if (Next->is(tok::identifier)) {
+// Peek the next token.

can you add comments explaining what syntax is being detected here?



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:1019
+FormatToken *NextNext = Tokens->getNextToken();
+Tokens->setPosition(StoredPosition);
+if (NextNext && NextNext->is(tok::equal))

parsePPEndIf uses a different method to peek - any opinion on why you're doing 
it differently here?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105087/new/

https://reviews.llvm.org/D105087

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105087: [clang-format] PR49960 clang-format doesn't handle ASI after "return" on JavaScript

2021-07-01 Thread Martin Probst via Phabricator via cfe-commits
mprobst accepted this revision.
mprobst added inline comments.



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:1001
+  if (TokenPosition < AllTokens.size()) {
+FormatToken *PeekNext = AllTokens[TokenPosition];
+return PeekNext;

nit: just `return AllTokens[TokenPosition]`?



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:1024
+// Don't go past the end of the file.
+if (!eof()) {
+  // Look for  return xxx = val; but not return xxx().

do you still need this, given peeknext protects against running past the doc 
end?



Comment at: clang/lib/Format/UnwrappedLineParser.h:188
 
+  // Peek to the next token
+  FormatToken *peekNextToken() const;

cam you document what this does to the "current token" pointer?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105087/new/

https://reviews.llvm.org/D105087

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115147: clang-format: [JS] test case for numeric separators.

2021-12-06 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
mprobst requested review of this revision.
Herald added a project: clang.

ES2021 allows numeric literals using `_` as a separator. This already
works, but had no test.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115147

Files:
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2692,5 +2692,9 @@
   "}\n");
 }
 
+TEST_F(FormatTestJS, NumericSeparators) {
+  verifyFormat("x = 1_000_000 + 12;", "x = 1_000_000   + 12;");
+}
+
 } // namespace format
 } // end namespace clang


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2692,5 +2692,9 @@
   "}\n");
 }
 
+TEST_F(FormatTestJS, NumericSeparators) {
+  verifyFormat("x = 1_000_000 + 12;", "x = 1_000_000   + 12;");
+}
+
 } // namespace format
 } // end namespace clang
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   >