[PATCH] D47193: clang-format: [JS] do not wrap before any `is`.
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`.
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
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
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
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
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.
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.
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 '{'
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 '{'
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 '{'
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 '{'
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 '{'
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.
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.
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.
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.
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.
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.
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
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
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
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
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.
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.
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.
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.
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.
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
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
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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`.
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`.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 `\\`.
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.
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.
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.
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.
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.
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
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 `\\`.
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 `\\`.
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 `\\`.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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
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.
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.
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
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
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.
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