r332968 - clang-format: [JS] do not wrap before any `is`.
Author: mprobst Date: Tue May 22 03:39:07 2018 New Revision: 332968 URL: http://llvm.org/viewvc/llvm-project?rev=332968&view=rev Log: clang-format: [JS] do not wrap before any `is`. Summary: `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. Reviewers: krasimir Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D47193 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=332968&r1=332967&r2=332968&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue May 22 03:39:07 2018 @@ -2958,7 +2958,7 @@ bool TokenAnnotator::canBreakBefore(cons 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; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=332968&r1=332967&r2=332968&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue May 22 03:39:07 2018 @@ -1164,7 +1164,15 @@ TEST_F(FormatTestJS, WrapRespectsAutomat 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
r338706 - clang-format: fix a crash in comment wraps.
Author: mprobst Date: Thu Aug 2 04:52:08 2018 New Revision: 338706 URL: http://llvm.org/viewvc/llvm-project?rev=338706&view=rev Log: clang-format: fix a crash in comment wraps. Summary: 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. Reviewers: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D50177 Modified: cfe/trunk/lib/Format/BreakableToken.cpp cfe/trunk/unittests/Format/FormatTestComments.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/BreakableToken.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/BreakableToken.cpp?rev=338706&r1=338705&r2=338706&view=diff == --- cfe/trunk/lib/Format/BreakableToken.cpp (original) +++ cfe/trunk/lib/Format/BreakableToken.cpp Thu Aug 2 04:52:08 2018 @@ -67,10 +67,11 @@ static BreakableToken::Split getCommentS 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 @@ static BreakableToken::Split getCommentS 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 @@ static BreakableToken::Split getCommentS 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 @@ BreakableComment::getSplit(unsigned Line 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 @@ void BreakableBlockComment::adaptStartOf 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 BreakL
r338837 - clang-format: [JS] don't break comments before any '{'
Author: mprobst Date: Fri Aug 3 02:34:41 2018 New Revision: 338837 URL: http://llvm.org/viewvc/llvm-project?rev=338837&view=rev Log: clang-format: [JS] don't break comments before any '{' Summary: 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. Reviewers: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D50230 Modified: cfe/trunk/lib/Format/BreakableToken.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/BreakableToken.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/BreakableToken.cpp?rev=338837&r1=338836&r2=338837&view=diff == --- cfe/trunk/lib/Format/BreakableToken.cpp (original) +++ cfe/trunk/lib/Format/BreakableToken.cpp Fri Aug 3 02:34:41 2018 @@ -90,19 +90,19 @@ static BreakableToken::Split getCommentS 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. Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=338837&r1=338836&r2=338837&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Aug 3 02:34:41 2018 @@ -2067,6 +2067,14 @@ TEST_F(FormatTestJS, JSDocAnnotations) { " * @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"; " */", ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: r338837 - clang-format: [JS] don't break comments before any '{'
Sorry about that, yes, that was me. Thanks for reverting! Tim Northover schrieb am Fr., 3. Aug. 2018 um 14:19 Uhr: > On Fri, 3 Aug 2018 at 11:47, Tim Northover > wrote: > > On Fri, 3 Aug 2018 at 10:34, Martin Probst via cfe-commits > > wrote: > > > clang-format: [JS] don't break comments before any '{' > > > > This looks like it's triggered a bunch of infinite loops in Clang's > > unittests. > > I've just taken a look at the normal lab.llvm.org bots and it looks > like *everything* is broken so I've reverted it for now. > > Cheers. > > Tim. > ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r338890 - clang-format: [JS] don't break comments before any '{'
Author: mprobst Date: Fri Aug 3 06:58:33 2018 New Revision: 338890 URL: http://llvm.org/viewvc/llvm-project?rev=338890&view=rev Log: clang-format: [JS] don't break comments before any '{' Summary: 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. Reviewers: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D50249 Modified: cfe/trunk/lib/Format/BreakableToken.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/BreakableToken.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/BreakableToken.cpp?rev=338890&r1=338889&r2=338890&view=diff == --- cfe/trunk/lib/Format/BreakableToken.cpp (original) +++ cfe/trunk/lib/Format/BreakableToken.cpp Fri Aug 3 06:58:33 2018 @@ -90,19 +90,21 @@ static BreakableToken::Split getCommentS 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. Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=338890&r1=338889&r2=338890&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Aug 3 06:58:33 2018 @@ -2067,6 +2067,14 @@ TEST_F(FormatTestJS, JSDocAnnotations) { " * @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"; " */", ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r325489 - clang-format: [JS] fix `of` detection.
Author: mprobst Date: Mon Feb 19 04:32:13 2018 New Revision: 325489 URL: http://llvm.org/viewvc/llvm-project?rev=325489&view=rev Log: clang-format: [JS] fix `of` detection. Summary: `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); Reviewers: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D43440 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=325489&r1=325488&r2=325489&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Feb 19 04:32:13 2018 @@ -2496,7 +2496,7 @@ bool TokenAnnotator::spaceRequiredBefore // (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; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=325489&r1=325488&r2=325489&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Feb 19 04:32:13 2018 @@ -294,6 +294,7 @@ TEST_F(FormatTestJS, ReservedWords) { 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
r304135 - clang-format: [JS] fix indenting bound functions.
Author: mprobst Date: Mon May 29 02:50:52 2017 New Revision: 304135 URL: http://llvm.org/viewvc/llvm-project?rev=304135&view=rev Log: clang-format: [JS] fix indenting bound functions. Summary: 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. Reviewers: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D33640 Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=304135&r1=304134&r2=304135&view=diff == --- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original) +++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Mon May 29 02:50:52 2017 @@ -215,7 +215,7 @@ bool ContinuationIndenter::mustBreak(con // ... // }.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 @@ unsigned ContinuationIndenter::getNewLin 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; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=304135&r1=304134&r2=304135&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon May 29 02:50:52 2017 @@ -717,6 +717,11 @@ TEST_F(FormatTestJS, FunctionLiterals) { " 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" ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r304141 - clang-format: [JS] do not clean up duplicated commas.
Author: mprobst Date: Mon May 29 03:41:11 2017 New Revision: 304141 URL: http://llvm.org/viewvc/llvm-project?rev=304141&view=rev Log: clang-format: [JS] do not clean up duplicated commas. Summary: In JavaScript, duplicated commas have semantic meaning. x = [a,,b]; The statement above creates an array with three entries, the middle being undefined. Because clang-format should not change semantics, disable this cleanup in JS. Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D33641 Modified: cfe/trunk/lib/Format/Format.cpp cfe/trunk/unittests/Format/CleanupTest.cpp Modified: cfe/trunk/lib/Format/Format.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=304141&r1=304140&r2=304141&view=diff == --- cfe/trunk/lib/Format/Format.cpp (original) +++ cfe/trunk/lib/Format/Format.cpp Mon May 29 03:41:11 2017 @@ -1910,6 +1910,9 @@ tooling::Replacements reformat(const For tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName) { + // cleanups only apply to C++ (they mostly concern ctor commas etc.) + if (Style.Language != FormatStyle::LK_Cpp) +return tooling::Replacements(); std::unique_ptr Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges); Cleaner Clean(*Env, Style); Modified: cfe/trunk/unittests/Format/CleanupTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/CleanupTest.cpp?rev=304141&r1=304140&r2=304141&view=diff == --- cfe/trunk/unittests/Format/CleanupTest.cpp (original) +++ cfe/trunk/unittests/Format/CleanupTest.cpp Mon May 29 03:41:11 2017 @@ -36,11 +36,12 @@ protected: // Returns code after cleanup around \p Offsets. std::string cleanupAroundOffsets(llvm::ArrayRef Offsets, - llvm::StringRef Code) { + llvm::StringRef Code, + const FormatStyle &Style = getLLVMStyle()) { std::vector Ranges; for (auto Offset : Offsets) Ranges.push_back(tooling::Range(Offset, 0)); -return cleanup(Code, Ranges); +return cleanup(Code, Ranges, Style); } }; @@ -171,6 +172,14 @@ TEST_F(CleanupTest, ListRedundantComma) EXPECT_EQ(Expected, cleanupAroundOffsets({17, 22}, Code)); } +TEST_F(CleanupTest, NoCleanupsForJavaScript) { + std::string Code = "function f() { var x = [a, b, , c]; }"; + std::string Expected = "function f() { var x = [a, b, , c]; }"; + const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript); + + EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code, Style)); +} + TEST_F(CleanupTest, TrailingCommaInParens) { std::string Code = "int main() { f(,1,,2,3,f(1,2,),4,,);}"; std::string Expected = "int main() { f(1,2,3,f(1,2),4);}"; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r304290 - clang-format: [JS] improve calculateBraceType heuristic
Author: mprobst Date: Wed May 31 04:29:40 2017 New Revision: 304290 URL: http://llvm.org/viewvc/llvm-project?rev=304290&view=rev Log: clang-format: [JS] improve calculateBraceType heuristic Summary: 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 code should have wrapped after "}", before "[". 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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D33714 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=304290&r1=304289&r2=304290&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Wed May 31 04:29:40 2017 @@ -360,16 +360,21 @@ void UnwrappedLineParser::calculateBrace 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 @@ void UnwrappedLineParser::calculateBrace // 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, Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=304290&r1=304289&r2=304290&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Wed May 31 04:29:40 2017 @@ -474,9 +474,8 @@ TEST_F(FormatTestJS, FormatsFreestanding "(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 @@ TEST_F(FormatTestJS, ClassDeclarations) 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}"); ___ cfe-commits mailing list cfe-commits@lists.l
r304791 - clang-format: [JS] Correctly Indent Nested JavaScript Literals.
Author: mprobst Date: Tue Jun 6 07:38:29 2017 New Revision: 304791 URL: http://llvm.org/viewvc/llvm-project?rev=304791&view=rev Log: clang-format: [JS] Correctly Indent Nested JavaScript Literals. Nested literals are sometimes only indented by 2 spaces, instead of respecting the IndentWidth option. There are existing unit tests (FormatTestJS.ArrayLiterals) that only pass because the style used to test them uses an IndentWidth of 2. This change removes the magic 2 and always uses the IndentWidth. I've added 6 tests. The first 4 of these tests fail before this change, while the last 2 already pass, but were added just to make sure it the change works with all types of braces. Patch originally by Jared Neil, thanks! Differential Revision: https://reviews.llvm.org/D33857 Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=304791&r1=304790&r2=304791&view=diff == --- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original) +++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Tue Jun 6 07:38:29 2017 @@ -1036,8 +1036,8 @@ void ContinuationIndenter::moveStatePast 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; } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=304791&r1=304790&r2=304791&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Jun 6 07:38:29 2017 @@ -1869,5 +1869,44 @@ TEST_F(FormatTestJS, Exponentiation) { 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 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r304904 - clang-format: [JS] recognize exported type definitions.
Author: mprobst Date: Wed Jun 7 07:53:22 2017 New Revision: 304904 URL: http://llvm.org/viewvc/llvm-project?rev=304904&view=rev Log: clang-format: [JS] recognize exported type definitions. Summary: Support "export type T = {...};", in addition to just "type T = {...};". Reviewers: klimek Differential Revision: https://reviews.llvm.org/D33980 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=304904&r1=304903&r2=304904&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Wed Jun 7 07:53:22 2017 @@ -135,8 +135,11 @@ private: if (Left->is(TT_OverloadedOperatorLParen)) { Contexts.back().IsExpression = false; } else if (Style.Language == FormatStyle::LK_JavaScript && - Line.startsWith(Keywords.kw_type, tok::identifier)) { + (Line.startsWith(Keywords.kw_type, tok::identifier) || +Line.startsWith(tok::kw_export, Keywords.kw_type, +tok::identifier))) { // type X = (...); + // export type X = (...); Contexts.back().IsExpression = false; } else if (Left->Previous && (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype, @@ -979,9 +982,12 @@ private: void modifyContext(const FormatToken &Current) { if (Current.getPrecedence() == prec::Assignment && !Line.First->isOneOf(tok::kw_template, tok::kw_using, tok::kw_return) && -// Type aliases use `type X = ...;` in TypeScript. +// Type aliases use `type X = ...;` in TypeScript and can be exported +// using `export type ...`. !(Style.Language == FormatStyle::LK_JavaScript && - Line.startsWith(Keywords.kw_type, tok::identifier)) && + (Line.startsWith(Keywords.kw_type, tok::identifier) || + Line.startsWith(tok::kw_export, Keywords.kw_type, + tok::identifier))) && (!Current.Previous || Current.Previous->isNot(tok::kw_operator))) { Contexts.back().IsExpression = true; if (!Line.startsWith(TT_UnaryOperator)) { Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=304904&r1=304903&r2=304904&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Wed Jun 7 07:53:22 2017 @@ -1226,6 +1226,12 @@ TEST_F(FormatTestJS, UnionIntersectionTy verifyFormat("let x: Bar|Baz;"); verifyFormat("let x: Bar|Baz;"); verifyFormat("let x: (Foo|Bar)[];"); + verifyFormat("type X = {\n" + " a: Foo|Bar;\n" + "};"); + verifyFormat("export type X = {\n" + " a: Foo|Bar;\n" + "};"); } TEST_F(FormatTestJS, ClassDeclarations) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r334415 - clang-format: [JS] strict prop init annotation.
Author: mprobst Date: Mon Jun 11 09:20:13 2018 New Revision: 334415 URL: http://llvm.org/viewvc/llvm-project?rev=334415&view=rev Log: clang-format: [JS] strict prop init annotation. Summary: 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. Reviewers: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D48030 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=334415&r1=334414&r2=334415&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Jun 11 09:20:13 2018 @@ -2981,7 +2981,7 @@ bool TokenAnnotator::mustBreakBefore(con // 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 @@ bool TokenAnnotator::canBreakBefore(cons 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)) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=334415&r1=334414&r2=334415&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Jun 11 09:20:13 2018 @@ -1540,6 +1540,15 @@ TEST_F(FormatTestJS, ClassDeclarations) "}"); } +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
r356447 - [clang-format] [JS] Don't break between template string and tag
Author: mprobst Date: Tue Mar 19 04:15:52 2019 New Revision: 356447 URL: http://llvm.org/viewvc/llvm-project?rev=356447&view=rev Log: [clang-format] [JS] Don't break between template string and tag Before: const x = veryLongIdentifier `hello`; After: const x = veryLongIdentifier`hello`; While it's allowed to have the template string and tag identifier separated by a line break, currently the clang-format output is not stable when a break is forced. Additionally, disallowing a line break makes it clear that the identifier is actually a tag for a template string. Patch originally by mitchellwills (thanks!). Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=356447&r1=356446&r2=356447&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Mar 19 04:15:52 2019 @@ -3171,6 +3171,11 @@ bool TokenAnnotator::canBreakBefore(cons return false; // must not break in "module foo { ...}" if (Right.is(TT_TemplateString) && Right.closesScope()) return false; +// Don't split tagged template literal so there is a break between the tag +// identifier and template string. +if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) { + return false; +} if (Left.is(TT_TemplateString) && Left.opensScope()) return true; } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=356447&r1=356446&r2=356447&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Mar 19 04:15:52 2019 @@ -1962,6 +1962,12 @@ TEST_F(FormatTestJS, NestedTemplateStrin TEST_F(FormatTestJS, TaggedTemplateStrings) { verifyFormat("var x = html``;"); verifyFormat("yield `hello`;"); + verifyFormat("var f = {\n" + " param: longTagName`This is a ${\n" + "'really'} long line`\n" + "};", + "var f = {param: longTagName`This is a ${'really'} long line`};", + getGoogleJSStyleWithColumns(40)); } TEST_F(FormatTestJS, CastSyntax) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r356449 - [clang-format] [JS] handle private members.
Author: mprobst Date: Tue Mar 19 05:28:41 2019 New Revision: 356449 URL: http://llvm.org/viewvc/llvm-project?rev=356449&view=rev Log: [clang-format] [JS] handle private members. Addresses PR40999 https://bugs.llvm.org/show_bug.cgi?id=40999 Private fields and methods in JavaScript would get incorrectly indented (it sees them as preprocessor directives and hence left aligns them) In this revision `#identifier` tokens `tok::hash->tok::identifier` are merged into a single new token `tok::identifier` with the `#` contained inside the TokenText. Before: ``` class Example { pub = 1; static pub2 = "foo"; static #priv2 = "bar"; method() { this.#priv = 5; } static staticMethod() { switch (this.#priv) { case '1': break; } } this.#privateMethod(); // infinite loop } static #staticPrivateMethod() {} } ``` After this fix the code will be correctly indented ``` class Example { pub = 1; #priv = 2; static pub2 = "foo"; static #priv2 = "bar"; method() { this.#priv = 5; } static staticMethod() { switch (this.#priv) { case '1': #priv = 3; break; } } #privateMethod() { this.#privateMethod(); // infinite loop } static #staticPrivateMethod() {} } ``` NOTE: There might be some JavaScript code out there which uses the C processor to preprocess .js files http://www.nongnu.org/espresso/js-cpp.html. It's not clear how this revision or even private fields and methods would interact. Patch originally by MyDeveloperDays (thanks!). Modified: cfe/trunk/lib/Format/FormatToken.h cfe/trunk/lib/Format/FormatTokenLexer.cpp cfe/trunk/lib/Format/FormatTokenLexer.h cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/FormatToken.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=356449&r1=356448&r2=356449&view=diff == --- cfe/trunk/lib/Format/FormatToken.h (original) +++ cfe/trunk/lib/Format/FormatToken.h Tue Mar 19 05:28:41 2019 @@ -60,6 +60,7 @@ namespace format { TYPE(JsExponentiationEqual) \ TYPE(JsFatArrow) \ TYPE(JsNonNullAssertion) \ + TYPE(JsPrivateIdentifier) \ TYPE(JsTypeColon) \ TYPE(JsTypeOperator) \ TYPE(JsTypeOptionalQuestion) \ Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.cpp?rev=356449&r1=356448&r2=356449&view=diff == --- cfe/trunk/lib/Format/FormatTokenLexer.cpp (original) +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp Tue Mar 19 05:28:41 2019 @@ -95,6 +95,8 @@ void FormatTokenLexer::tryMergePreviousT Tokens.back()->Tok.setKind(tok::starequal); return; } +if (tryMergeJSPrivateIdentifier()) + return; } if (Style.Language == FormatStyle::LK_Java) { @@ -120,6 +122,25 @@ bool FormatTokenLexer::tryMergeNSStringL Tokens.erase(Tokens.end() - 1); return true; } + +bool FormatTokenLexer::tryMergeJSPrivateIdentifier() { + // Merges #idenfier into a single identifier with the text #identifier + // but the token tok::identifier. + if (Tokens.size() < 2) +return false; + auto &Hash = *(Tokens.end() - 2); + auto &Identifier = *(Tokens.end() - 1); + if (!Hash->is(tok::hash) || !Identifier->is(tok::identifier)) +return false; + Hash->Tok.setKind(tok::identifier); + Hash->TokenText = + StringRef(Hash->TokenText.begin(), +Identifier->TokenText.end() - Hash->TokenText.begin()); + Hash->ColumnWidth += Identifier->ColumnWidth; + Hash->Type = TT_JsPrivateIdentifier; + Tokens.erase(Tokens.end() - 1); + return true; +} bool FormatTokenLexer::tryMergeLessLess() { // Merge X,less,less,Y into X,lessless,Y unless X or Y is less. Modified: cfe/trunk/lib/Format/FormatTokenLexer.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.h?rev=356449&r1=356448&r2=356449&view=diff == --- cfe/trunk/lib/Format/FormatTokenLexer.h (original) +++ cfe/trunk/lib/Format/FormatTokenLexer.h Tue Mar 19 05:28:41 2019 @@ -48,6 +48,7 @@ private: bool tryMergeLessLess(); bool tryMergeNSStringLiteral(); + bool tryMergeJSPrivateIdentifier(); bool tryMergeTokens(ArrayRef Kinds, TokenType NewType); Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=356449&r1=356448&r2=356449&view=diff =
r343080 - clang-format: [JS] space after parameter naming.
Author: mprobst Date: Wed Sep 26 01:28:33 2018 New Revision: 343080 URL: http://llvm.org/viewvc/llvm-project?rev=343080&view=rev Log: clang-format: [JS] space after parameter naming. Summary: Previously: foo(/*bar=*/baz); Now: foo(/*bar=*/ baz); The run-in parameter naming comment is not intended in JS. Reviewers: mboehme Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D52535 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=343080&r1=343079&r2=343080&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Wed Sep 26 01:28:33 2018 @@ -2517,7 +2517,9 @@ bool TokenAnnotator::spaceRequiredBetwee 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))) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=343080&r1=343079&r2=343080&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Wed Sep 26 01:28:33 2018 @@ -2304,5 +2304,9 @@ TEST_F(FormatTestJS, AddsLastLinePenalty "};")); } +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
r343179 - clang-format: [JS] conditional types.
Author: mprobst Date: Wed Sep 26 23:48:13 2018 New Revision: 343179 URL: http://llvm.org/viewvc/llvm-project?rev=343179&view=rev Log: clang-format: [JS] conditional types. Summary: 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. Reviewers: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D52536 Modified: cfe/trunk/lib/Format/FormatToken.h cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/FormatToken.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=343179&r1=343178&r2=343179&view=diff == --- cfe/trunk/lib/Format/FormatToken.h (original) +++ cfe/trunk/lib/Format/FormatToken.h Wed Sep 26 23:48:13 2018 @@ -680,6 +680,7 @@ struct AdditionalKeywords { 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 @@ struct AdditionalKeywords { IdentifierInfo *kw_function; IdentifierInfo *kw_get; IdentifierInfo *kw_import; + IdentifierInfo *kw_infer; IdentifierInfo *kw_is; IdentifierInfo *kw_let; IdentifierInfo *kw_module; Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=343179&r1=343178&r2=343179&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Wed Sep 26 23:48:13 2018 @@ -3088,6 +3088,12 @@ bool TokenAnnotator::canBreakBefore(cons 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)) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=343179&r1=343178&r2=343179&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Wed Sep 26 23:48:13 2018 @@ -2308,5 +2308,14 @@ TEST_F(FormatTestJS, ParameterNamingComm 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 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r311988 - clang-format: [JS] simplify template string wrapping.
Author: mprobst Date: Tue Aug 29 01:30:07 2017 New Revision: 311988 URL: http://llvm.org/viewvc/llvm-project?rev=311988&view=rev Log: clang-format: [JS] simplify template string wrapping. Summary: 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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D37142 Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=311988&r1=311987&r2=311988&view=diff == --- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original) +++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Tue Aug 29 01:30:07 2017 @@ -661,9 +661,7 @@ unsigned ContinuationIndenter::addTokenO // 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 @@ unsigned ContinuationIndenter::moveState 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 @@ void ContinuationIndenter::moveStatePast 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() && Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=311988&r1=311987&r2=311988&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 29 01:30:07 2017 @@ -1793,32 +1793,28 @@ TEST_F(FormatTestJS, TemplateStrings) { 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: ${\
r312918 - clang-format: [JS] wrap and indent `goog.setTestOnly` calls.
Author: mprobst Date: Mon Sep 11 08:22:52 2017 New Revision: 312918 URL: http://llvm.org/viewvc/llvm-project?rev=312918&view=rev Log: clang-format: [JS] wrap and indent `goog.setTestOnly` calls. Summary: While `goog.setTestOnly` usually appears in the imports section of a file, it is not actually an import, and also usually doesn't take long parameters (nor namespaces as a parameter, it's a description/message that should be wrapped). This fixes a regression where a `goog.setTestOnly` call nested in a function was not wrapped. Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D37685 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=312918&r1=312917&r2=312918&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Sep 11 08:22:52 2017 @@ -960,7 +960,6 @@ private: Tok.Next->Next && (Tok.Next->Next->TokenText == "module" || Tok.Next->Next->TokenText == "provide" || Tok.Next->Next->TokenText == "require" || - Tok.Next->Next->TokenText == "setTestOnly" || Tok.Next->Next->TokenText == "forwardDeclare") && Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren); } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=312918&r1=312917&r2=312918&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Sep 11 08:22:52 2017 @@ -558,8 +558,6 @@ TEST_F(FormatTestJS, GoogModules) { getGoogleJSStyleWithColumns(40)); verifyFormat("var long = goog.require('this.is.really.absurdly.long');", getGoogleJSStyleWithColumns(40)); - verifyFormat("goog.setTestOnly('this.is.really.absurdly.long');", - getGoogleJSStyleWithColumns(40)); verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');", getGoogleJSStyleWithColumns(40)); @@ -567,6 +565,12 @@ TEST_F(FormatTestJS, GoogModules) { verifyFormat( "var MyLongClassName =\n" " goog.module.get('my.long.module.name.followedBy.MyLongClassName');"); + verifyFormat("function a() {\n" + " goog.setTestOnly();\n" + "}\n", + "function a() {\n" + "goog.setTestOnly();\n" + "}\n"); } TEST_F(FormatTestJS, FormatsNamespaces) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r350516 - clang-format: [JS] support goog.requireType.
Author: mprobst Date: Mon Jan 7 05:12:50 2019 New Revision: 350516 URL: http://llvm.org/viewvc/llvm-project?rev=350516&view=rev Log: clang-format: [JS] support goog.requireType. Summary: It's a new primitive for importing symbols, and should be treated like the (previously handled) `goog.require` and `goog.forwardDeclare`. Reviewers: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D56385 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=350516&r1=350515&r2=350516&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Jan 7 05:12:50 2019 @@ -1123,6 +1123,7 @@ private: (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); } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=350516&r1=350515&r2=350516&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Jan 7 05:12:50 2019 @@ -600,6 +600,8 @@ TEST_F(FormatTestJS, GoogModules) { 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
[clang] 146d685 - clang-format: [JS] detect C++ keywords.
Author: Martin Probst Date: 2020-04-03T14:23:56+02:00 New Revision: 146d685cd657399a4698015f16cc5910cc828728 URL: https://github.com/llvm/llvm-project/commit/146d685cd657399a4698015f16cc5910cc828728 DIFF: https://github.com/llvm/llvm-project/commit/146d685cd657399a4698015f16cc5910cc828728.diff LOG: clang-format: [JS] detect C++ keywords. Summary: C++ defines a number of keywords that are regular identifiers in JavaScript, e.g. `concept`: const concept = 1; // legit JS This change expands the existing `IsJavaScriptIdentifier(Tok)` function to return false for C++ keywords that aren't keywords in JS. Reviewers: krasimir Subscribers: jfb, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D77311 Added: Modified: clang/lib/Format/FormatToken.h clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 10a5f0e96f96..48ec7602c21c 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -910,9 +910,64 @@ struct AdditionalKeywords { /// 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 { -return Tok.is(tok::identifier) && - JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) == - JsExtraKeywords.end(); +// 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()) { +case tok::kw_break: +case tok::kw_case: +case tok::kw_catch: +case tok::kw_class: +case tok::kw_continue: +case tok::kw_const: +case tok::kw_default: +case tok::kw_delete: +case tok::kw_do: +case tok::kw_else: +case tok::kw_enum: +case tok::kw_export: +case tok::kw_false: +case tok::kw_for: +case tok::kw_if: +case tok::kw_import: +case tok::kw_module: +case tok::kw_new: +case tok::kw_private: +case tok::kw_protected: +case tok::kw_public: +case tok::kw_return: +case tok::kw_static: +case tok::kw_switch: +case tok::kw_this: +case tok::kw_throw: +case tok::kw_true: +case tok::kw_try: +case tok::kw_typeof: +case tok::kw_void: +case tok::kw_while: + // These are JS keywords that are lexed by LLVM/clang as keywords. + return false; +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(); +default: + // Other keywords are handled in the switch below, to avoid problems due + // to duplicate case labels when using the #include trick. + break; +} + +switch (Tok.Tok.getKind()) { + // Handle C++ keywords not included above: these are all JS identifiers. +#define KEYWORD(X, Y) case tok::kw_##X: +#include "clang/Basic/TokenKinds.def" + // #undef KEYWORD is not needed -- it's #undef-ed at the end of + // TokenKinds.def + return true; +default: + // All other tokens (punctuation etc) are not JS identifiers. + return false; +} } /// Returns \c true if \p Tok is a C# keyword, returns diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index a3cd4f42f8f8..029741c3dce7 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1522,9 +1522,9 @@ class AnnotatingParser { 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 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, (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(Lef
[clang] 9220150 - clang-format: [JS] handle pseudo-keywords.
Author: Martin Probst Date: 2020-04-06T17:13:04+02:00 New Revision: 92201505cdecd8ba5795f5e33821c49dc57f0816 URL: https://github.com/llvm/llvm-project/commit/92201505cdecd8ba5795f5e33821c49dc57f0816 DIFF: https://github.com/llvm/llvm-project/commit/92201505cdecd8ba5795f5e33821c49dc57f0816.diff LOG: clang-format: [JS] handle pseudo-keywords. Summary: 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. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D77548 Added: Modified: clang/lib/Format/FormatToken.h clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 48ec7602c21c..c67cf192ab1f 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -909,7 +909,11 @@ struct AdditionalKeywords { /// 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 @@ struct AdditionalKeywords { 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. diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 029741c3dce7..8204623645a4 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1522,9 +1522,11 @@ class AnnotatingParser { 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 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, 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)) diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 3fd795c526b1..eadea35f051a 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -2412,6 +2412,11 @
[PATCH] D24708: clang-format: [JS] Fix line breaks before comments when sorting imports.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. Previously, clang-format would always insert an additional line break after the import block if the main body started with a comment, due to loosing track of the first non-import line. https://reviews.llvm.org/D24708 Files: lib/Format/SortJavaScriptImports.cpp unittests/Format/SortImportsTestJS.cpp Index: unittests/Format/SortImportsTestJS.cpp === --- unittests/Format/SortImportsTestJS.cpp +++ unittests/Format/SortImportsTestJS.cpp @@ -121,6 +121,16 @@ "import {sym} from 'b'; // from //foo:bar\n" "// A very important import follows.\n" "import {sym} from 'a'; /* more comments */\n"); + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n", + "import {sym} from 'b';\n" + "import {sym} from 'a';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n"); } TEST_F(SortImportsTestJS, SortStar) { Index: lib/Format/SortJavaScriptImports.cpp === --- lib/Format/SortJavaScriptImports.cpp +++ lib/Format/SortJavaScriptImports.cpp @@ -293,14 +293,19 @@ // of the import that immediately follows them by using the previously // set Start. Start = Line->First->Tok.getLocation(); - if (!Current) -continue; // Only comments on this line. + if (!Current) { +// Only comments on this line. Could be the first non-import line. +FirstNonImportLine = Line; +continue; + } JsModuleReference Reference; Reference.Range.setBegin(Start); if (!parseModuleReference(Keywords, Reference)) { -FirstNonImportLine = Line; +if (!FirstNonImportLine) + FirstNonImportLine = Line; // if no comment before. break; } + FirstNonImportLine = nullptr; AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ Index: unittests/Format/SortImportsTestJS.cpp === --- unittests/Format/SortImportsTestJS.cpp +++ unittests/Format/SortImportsTestJS.cpp @@ -121,6 +121,16 @@ "import {sym} from 'b'; // from //foo:bar\n" "// A very important import follows.\n" "import {sym} from 'a'; /* more comments */\n"); + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n", + "import {sym} from 'b';\n" + "import {sym} from 'a';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n"); } TEST_F(SortImportsTestJS, SortStar) { Index: lib/Format/SortJavaScriptImports.cpp === --- lib/Format/SortJavaScriptImports.cpp +++ lib/Format/SortJavaScriptImports.cpp @@ -293,14 +293,19 @@ // of the import that immediately follows them by using the previously // set Start. Start = Line->First->Tok.getLocation(); - if (!Current) -continue; // Only comments on this line. + if (!Current) { +// Only comments on this line. Could be the first non-import line. +FirstNonImportLine = Line; +continue; + } JsModuleReference Reference; Reference.Range.setBegin(Start); if (!parseModuleReference(Keywords, Reference)) { -FirstNonImportLine = Line; +if (!FirstNonImportLine) + FirstNonImportLine = Line; // if no comment before. break; } + FirstNonImportLine = nullptr; AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r281856 - clang-format: [JS] ASI insertion after boolean literals.
Author: mprobst Date: Sun Sep 18 12:21:52 2016 New Revision: 281856 URL: http://llvm.org/viewvc/llvm-project?rev=281856&view=rev Log: clang-format: [JS] ASI insertion after boolean literals. Summary: Before when a semicolon was missing after a boolean literal: a = true return 1; clang-format would parse this as one line and format as: a = true return 1; It turns out that C++ does not consider `true` and `false` to be literals, we have to check for that explicitly. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D24574 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=281856&r1=281855&r2=281856&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Sun Sep 18 12:21:52 2016 @@ -681,7 +681,9 @@ static bool mustBeJSIdent(const Addition static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords, const FormatToken *FormatTok) { - return FormatTok->Tok.isLiteral() || mustBeJSIdent(Keywords, FormatTok); + return FormatTok->Tok.isLiteral() || + FormatTok->isOneOf(tok::kw_true, tok::kw_false) || + mustBeJSIdent(Keywords, FormatTok); } // isJSDeclOrStmt returns true if |FormatTok| starts a declaration or statement Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=281856&r1=281855&r2=281856&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sun Sep 18 12:21:52 2016 @@ -774,6 +774,18 @@ TEST_F(FormatTestJS, AutomaticSemicolonI "String"); verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n" " bar) {}"); + verifyFormat("a = true\n" + "return 1", + "a = true\n" + " return 1"); + verifyFormat("a = 's'\n" + "return 1", + "a = 's'\n" + " return 1"); + verifyFormat("a = null\n" + "return 1", + "a = null\n" + " return 1"); } TEST_F(FormatTestJS, ClosureStyleCasts) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24574: clang-format: [JS] ASI insertion after boolean literals.
This revision was automatically updated to reflect the committed changes. Closed by commit rL281856: clang-format: [JS] ASI insertion after boolean literals. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D24574?vs=71385&id=71755#toc Repository: rL LLVM https://reviews.llvm.org/D24574 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 @@ -681,7 +681,9 @@ static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords, const FormatToken *FormatTok) { - return FormatTok->Tok.isLiteral() || mustBeJSIdent(Keywords, FormatTok); + return FormatTok->Tok.isLiteral() || + FormatTok->isOneOf(tok::kw_true, tok::kw_false) || + mustBeJSIdent(Keywords, FormatTok); } // isJSDeclOrStmt returns true if |FormatTok| starts a declaration or statement Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -774,6 +774,18 @@ "String"); verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n" " bar) {}"); + verifyFormat("a = true\n" + "return 1", + "a = true\n" + " return 1"); + verifyFormat("a = 's'\n" + "return 1", + "a = 's'\n" + " return 1"); + verifyFormat("a = null\n" + "return 1", + "a = null\n" + " return 1"); } TEST_F(FormatTestJS, ClosureStyleCasts) { Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp === --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp @@ -681,7 +681,9 @@ static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords, const FormatToken *FormatTok) { - return FormatTok->Tok.isLiteral() || mustBeJSIdent(Keywords, FormatTok); + return FormatTok->Tok.isLiteral() || + FormatTok->isOneOf(tok::kw_true, tok::kw_false) || + mustBeJSIdent(Keywords, FormatTok); } // isJSDeclOrStmt returns true if |FormatTok| starts a declaration or statement Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -774,6 +774,18 @@ "String"); verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n" " bar) {}"); + verifyFormat("a = true\n" + "return 1", + "a = true\n" + " return 1"); + verifyFormat("a = 's'\n" + "return 1", + "a = 's'\n" + " return 1"); + verifyFormat("a = null\n" + "return 1", + "a = null\n" + " return 1"); } TEST_F(FormatTestJS, ClosureStyleCasts) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r281857 - clang-format: [JS] Do not wrap taze annotation comments.
Author: mprobst Date: Sun Sep 18 12:33:51 2016 New Revision: 281857 URL: http://llvm.org/viewvc/llvm-project?rev=281857&view=rev Log: clang-format: [JS] Do not wrap taze annotation comments. Summary: `// taze: ... from ...` comments are used help tools where a specific global symbol comes from. Before: // taze: many, different, symbols from // 'some_long_location_here' After: // taze: many, different, symbols from 'some_long_location_here' Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D24477 Modified: cfe/trunk/lib/Format/Format.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/Format.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=281857&r1=281856&r2=281857&view=diff == --- cfe/trunk/lib/Format/Format.cpp (original) +++ cfe/trunk/lib/Format/Format.cpp Sun Sep 18 12:33:51 2016 @@ -613,7 +613,7 @@ FormatStyle getGoogleStyle(FormatStyle:: GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "@(export|requirecss|return|see|visibility) "; +GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=281857&r1=281856&r2=281857&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sun Sep 18 12:33:51 2016 @@ -1444,5 +1444,11 @@ TEST_F(FormatTestJS, Conditional) { "}"); } +TEST_F(FormatTestJS, ImportComments) { + verifyFormat("import {x} from 'x'; // from some location", + getGoogleJSStyleWithColumns(25)); + verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10)); +} + } // 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
Re: [PATCH] D24477: clang-format: [JS] Do not wrap taze: IWYU comments
This revision was automatically updated to reflect the committed changes. Closed by commit rL281857: clang-format: [JS] Do not wrap taze annotation comments. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D24477?vs=71189&id=71756#toc Repository: rL LLVM https://reviews.llvm.org/D24477 Files: cfe/trunk/lib/Format/Format.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Index: cfe/trunk/lib/Format/Format.cpp === --- cfe/trunk/lib/Format/Format.cpp +++ cfe/trunk/lib/Format/Format.cpp @@ -613,7 +613,7 @@ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "@(export|requirecss|return|see|visibility) "; +GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -1444,5 +1444,11 @@ "}"); } +TEST_F(FormatTestJS, ImportComments) { + verifyFormat("import {x} from 'x'; // from some location", + getGoogleJSStyleWithColumns(25)); + verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10)); +} + } // end namespace tooling } // end namespace clang Index: cfe/trunk/lib/Format/Format.cpp === --- cfe/trunk/lib/Format/Format.cpp +++ cfe/trunk/lib/Format/Format.cpp @@ -613,7 +613,7 @@ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "@(export|requirecss|return|see|visibility) "; +GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -1444,5 +1444,11 @@ "}"); } +TEST_F(FormatTestJS, ImportComments) { + verifyFormat("import {x} from 'x'; // from some location", + getGoogleJSStyleWithColumns(25)); + verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10)); +} + } // 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
r281888 - clang-format: [JS] Fix line breaks before comments when sorting imports.
Author: mprobst Date: Mon Sep 19 02:02:34 2016 New Revision: 281888 URL: http://llvm.org/viewvc/llvm-project?rev=281888&view=rev Log: clang-format: [JS] Fix line breaks before comments when sorting imports. Summary: Previously, clang-format would always insert an additional line break after the import block if the main body started with a comment, due to loosing track of the first non-import line. Reviewers: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D24708 Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp cfe/trunk/unittests/Format/SortImportsTestJS.cpp Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/SortJavaScriptImports.cpp?rev=281888&r1=281887&r2=281888&view=diff == --- cfe/trunk/lib/Format/SortJavaScriptImports.cpp (original) +++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp Mon Sep 19 02:02:34 2016 @@ -293,14 +293,19 @@ private: // of the import that immediately follows them by using the previously // set Start. Start = Line->First->Tok.getLocation(); - if (!Current) -continue; // Only comments on this line. + if (!Current) { +// Only comments on this line. Could be the first non-import line. +FirstNonImportLine = Line; +continue; + } JsModuleReference Reference; Reference.Range.setBegin(Start); if (!parseModuleReference(Keywords, Reference)) { -FirstNonImportLine = Line; +if (!FirstNonImportLine) + FirstNonImportLine = Line; // if no comment before. break; } + FirstNonImportLine = nullptr; AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ Modified: cfe/trunk/unittests/Format/SortImportsTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/SortImportsTestJS.cpp?rev=281888&r1=281887&r2=281888&view=diff == --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp (original) +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp Mon Sep 19 02:02:34 2016 @@ -121,6 +121,16 @@ TEST_F(SortImportsTestJS, Comments) { "import {sym} from 'b'; // from //foo:bar\n" "// A very important import follows.\n" "import {sym} from 'a'; /* more comments */\n"); + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n", + "import {sym} from 'b';\n" + "import {sym} from 'a';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n"); } TEST_F(SortImportsTestJS, SortStar) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24708: clang-format: [JS] Fix line breaks before comments when sorting imports.
This revision was automatically updated to reflect the committed changes. Closed by commit rL281888: clang-format: [JS] Fix line breaks before comments when sorting imports. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D24708?vs=71754&id=71772#toc Repository: rL LLVM https://reviews.llvm.org/D24708 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 @@ -293,14 +293,19 @@ // of the import that immediately follows them by using the previously // set Start. Start = Line->First->Tok.getLocation(); - if (!Current) -continue; // Only comments on this line. + if (!Current) { +// Only comments on this line. Could be the first non-import line. +FirstNonImportLine = Line; +continue; + } JsModuleReference Reference; Reference.Range.setBegin(Start); if (!parseModuleReference(Keywords, Reference)) { -FirstNonImportLine = Line; +if (!FirstNonImportLine) + FirstNonImportLine = Line; // if no comment before. break; } + FirstNonImportLine = nullptr; AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ Index: cfe/trunk/unittests/Format/SortImportsTestJS.cpp === --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp @@ -121,6 +121,16 @@ "import {sym} from 'b'; // from //foo:bar\n" "// A very important import follows.\n" "import {sym} from 'a'; /* more comments */\n"); + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n", + "import {sym} from 'b';\n" + "import {sym} from 'a';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n"); } TEST_F(SortImportsTestJS, SortStar) { Index: cfe/trunk/lib/Format/SortJavaScriptImports.cpp === --- cfe/trunk/lib/Format/SortJavaScriptImports.cpp +++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp @@ -293,14 +293,19 @@ // of the import that immediately follows them by using the previously // set Start. Start = Line->First->Tok.getLocation(); - if (!Current) -continue; // Only comments on this line. + if (!Current) { +// Only comments on this line. Could be the first non-import line. +FirstNonImportLine = Line; +continue; + } JsModuleReference Reference; Reference.Range.setBegin(Start); if (!parseModuleReference(Keywords, Reference)) { -FirstNonImportLine = Line; +if (!FirstNonImportLine) + FirstNonImportLine = Line; // if no comment before. break; } + FirstNonImportLine = nullptr; AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ Index: cfe/trunk/unittests/Format/SortImportsTestJS.cpp === --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp @@ -121,6 +121,16 @@ "import {sym} from 'b'; // from //foo:bar\n" "// A very important import follows.\n" "import {sym} from 'a'; /* more comments */\n"); + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n", + "import {sym} from 'b';\n" + "import {sym} from 'a';\n" + "\n" + "/** Comment on variable. */\n" + "const x = 1;\n"); } TEST_F(SortImportsTestJS, SortStar) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D24767: clang-format: [JS] do not wrapp @returns tags.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. @returns is incorrect code, the standard is @return. However wrapping it can still confuse users. https://reviews.llvm.org/D24767 Files: lib/Format/Format.cpp Index: lib/Format/Format.cpp === --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -613,7 +613,8 @@ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; +GoogleStyle.CommentPragmas = +"(taze:|@(export|requirecss|return|returns|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; Index: lib/Format/Format.cpp === --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -613,7 +613,8 @@ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; +GoogleStyle.CommentPragmas = +"(taze:|@(export|requirecss|return|returns|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r282056 - clang-format: [JS] do not wrapp @returns tags.
Author: mprobst Date: Wed Sep 21 01:56:38 2016 New Revision: 282056 URL: http://llvm.org/viewvc/llvm-project?rev=282056&view=rev Log: clang-format: [JS] do not wrapp @returns tags. Summary: @returns is incorrect code, the standard is @return. However wrapping it can still confuse users. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D24767 Modified: cfe/trunk/lib/Format/Format.cpp Modified: cfe/trunk/lib/Format/Format.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=282056&r1=282055&r2=282056&view=diff == --- cfe/trunk/lib/Format/Format.cpp (original) +++ cfe/trunk/lib/Format/Format.cpp Wed Sep 21 01:56:38 2016 @@ -613,7 +613,8 @@ FormatStyle getGoogleStyle(FormatStyle:: GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; +GoogleStyle.CommentPragmas = +"(taze:|@(export|requirecss|return|returns|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24767: clang-format: [JS] do not wrapp @returns tags.
This revision was automatically updated to reflect the committed changes. Closed by commit rL282056: clang-format: [JS] do not wrapp @returns tags. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D24767?vs=71938&id=72010#toc Repository: rL LLVM https://reviews.llvm.org/D24767 Files: cfe/trunk/lib/Format/Format.cpp Index: cfe/trunk/lib/Format/Format.cpp === --- cfe/trunk/lib/Format/Format.cpp +++ cfe/trunk/lib/Format/Format.cpp @@ -613,7 +613,8 @@ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; +GoogleStyle.CommentPragmas = +"(taze:|@(export|requirecss|return|returns|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; Index: cfe/trunk/lib/Format/Format.cpp === --- cfe/trunk/lib/Format/Format.cpp +++ cfe/trunk/lib/Format/Format.cpp @@ -613,7 +613,8 @@ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -GoogleStyle.CommentPragmas = "(taze:|@(export|requirecss|return|see|visibility)) "; +GoogleStyle.CommentPragmas = +"(taze:|@(export|requirecss|return|returns|see|visibility)) "; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D24804: clang-format: [JS] reserved words in method names.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. Before: class X { delete () { ... } } After: class X { delete() { ... } } https://reviews.llvm.org/D24804 Files: lib/Format/TokenAnnotator.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -147,6 +147,18 @@ verifyFormat("x = interface instanceof y;"); } +TEST_F(FormatTestJS, ReservedWordsMethods) { + verifyFormat( + "class X {\n" + " delete() {\n" + "x();\n" + " }\n" + " interface() {\n" + "x();\n" + " }\n" + "}\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 @@ -2158,6 +2158,10 @@ tok::r_square, tok::r_brace) || Left.Tok.isLiteral())) return false; +// 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 (Left.is(tok::exclaim) && Right.is(Keywords.kw_as)) return true; // "x! as string" } else if (Style.Language == FormatStyle::LK_Java) { Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -147,6 +147,18 @@ verifyFormat("x = interface instanceof y;"); } +TEST_F(FormatTestJS, ReservedWordsMethods) { + verifyFormat( + "class X {\n" + " delete() {\n" + "x();\n" + " }\n" + " interface() {\n" + "x();\n" + " }\n" + "}\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 @@ -2158,6 +2158,10 @@ tok::r_square, tok::r_brace) || Left.Tok.isLiteral())) return false; +// 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 (Left.is(tok::exclaim) && Right.is(Keywords.kw_as)) return true; // "x! as string" } else if (Style.Language == FormatStyle::LK_Java) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24804: clang-format: [JS] reserved words in method names.
mprobst updated this revision to Diff 72061. mprobst added a comment. - move up to support let in methods. https://reviews.llvm.org/D24804 Files: lib/Format/TokenAnnotator.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -147,6 +147,21 @@ verifyFormat("x = interface instanceof y;"); } +TEST_F(FormatTestJS, ReservedWordsMethods) { + verifyFormat( + "class X {\n" + " delete() {\n" + "x();\n" + " }\n" + " interface() {\n" + "x();\n" + " }\n" + " let() {\n" + "x();\n" + " }\n" + "}\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 @@ -2125,6 +2125,10 @@ if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; +// 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 (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -147,6 +147,21 @@ verifyFormat("x = interface instanceof y;"); } +TEST_F(FormatTestJS, ReservedWordsMethods) { + verifyFormat( + "class X {\n" + " delete() {\n" + "x();\n" + " }\n" + " interface() {\n" + "x();\n" + " }\n" + " let() {\n" + "x();\n" + " }\n" + "}\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 @@ -2125,6 +2125,10 @@ if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; +// 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 (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24804: clang-format: [JS] reserved words in method names.
This revision was automatically updated to reflect the committed changes. Closed by commit rL282138: clang-format: [JS] reserved words in method names. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D24804?vs=72061&id=72140#toc Repository: rL LLVM https://reviews.llvm.org/D24804 Files: cfe/trunk/lib/Format/TokenAnnotator.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 @@ -147,6 +147,21 @@ verifyFormat("x = interface instanceof y;"); } +TEST_F(FormatTestJS, ReservedWordsMethods) { + verifyFormat( + "class X {\n" + " delete() {\n" + "x();\n" + " }\n" + " interface() {\n" + "x();\n" + " }\n" + " let() {\n" + "x();\n" + " }\n" + "}\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 @@ -2125,6 +2125,10 @@ if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; +// 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 (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -147,6 +147,21 @@ verifyFormat("x = interface instanceof y;"); } +TEST_F(FormatTestJS, ReservedWordsMethods) { + verifyFormat( + "class X {\n" + " delete() {\n" + "x();\n" + " }\n" + " interface() {\n" + "x();\n" + " }\n" + " let() {\n" + "x();\n" + " }\n" + "}\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 @@ -2125,6 +2125,10 @@ if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; +// 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 (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r282138 - clang-format: [JS] reserved words in method names.
Author: mprobst Date: Thu Sep 22 02:18:00 2016 New Revision: 282138 URL: http://llvm.org/viewvc/llvm-project?rev=282138&view=rev Log: clang-format: [JS] reserved words in method names. Summary: Before: class X { delete () { ... } } After: class X { delete() { ... } } Reviewers: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D24804 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=282138&r1=282137&r2=282138&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Thu Sep 22 02:18:00 2016 @@ -2125,6 +2125,10 @@ bool TokenAnnotator::spaceRequiredBefore if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; +// 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 (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=282138&r1=282137&r2=282138&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Thu Sep 22 02:18:00 2016 @@ -147,6 +147,21 @@ TEST_F(FormatTestJS, ReservedWords) { verifyFormat("x = interface instanceof y;"); } +TEST_F(FormatTestJS, ReservedWordsMethods) { + verifyFormat( + "class X {\n" + " delete() {\n" + "x();\n" + " }\n" + " interface() {\n" + "x();\n" + " }\n" + " let() {\n" + "x();\n" + " }\n" + "}\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] D25439: Fixed column shift when formatting line containing bit shift operators
mprobst added a comment. Looks good to me, but Daniel is a better owner for this code. https://reviews.llvm.org/D25439 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D25675: clang-format: [JS] Fix template string ASI.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. Previously, automatic semicolon insertion would add an unwrapped line when a template string contained a line break. var x = `foo${ bar}`; Would be formatted with `bar...` on a separate line and no indent. https://reviews.llvm.org/D25675 Files: lib/Format/UnwrappedLineParser.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1276,6 +1276,12 @@ verifyFormat("var x = ` \\${foo}`;\n"); } +TEST_F(FormatTestJS, TemplateStringASI) { + verifyFormat("var x = `hello${world}`;", "var x = `hello${\n" + "world\n" + "}`;"); +} + TEST_F(FormatTestJS, NestedTemplateStrings) { verifyFormat( "var x = `${xs.map(x => `${x}`).join('\\n')}`;"); Index: lib/Format/UnwrappedLineParser.cpp === --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -727,6 +727,8 @@ return; 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. @@ -737,9 +739,12 @@ if (Next->is(tok::exclaim) && PreviousMustBeValue) addUnwrappedLine(); bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next); - if (NextMustBeValue && (PreviousMustBeValue || - Previous->isOneOf(tok::r_square, tok::r_paren, -tok::plusplus, tok::minusminus))) + bool NextEndsTemplateExpr = + Next->is(TT_TemplateString) && Next->TokenText.startswith("}"); + if (NextMustBeValue && !NextEndsTemplateExpr && !PreviousStartsTemplateExpr && + (PreviousMustBeValue || + Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus, + tok::minusminus))) addUnwrappedLine(); if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next)) addUnwrappedLine(); Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1276,6 +1276,12 @@ verifyFormat("var x = ` \\${foo}`;\n"); } +TEST_F(FormatTestJS, TemplateStringASI) { + verifyFormat("var x = `hello${world}`;", "var x = `hello${\n" + "world\n" + "}`;"); +} + TEST_F(FormatTestJS, NestedTemplateStrings) { verifyFormat( "var x = `${xs.map(x => `${x}`).join('\\n')}`;"); Index: lib/Format/UnwrappedLineParser.cpp === --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -727,6 +727,8 @@ return; 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. @@ -737,9 +739,12 @@ if (Next->is(tok::exclaim) && PreviousMustBeValue) addUnwrappedLine(); bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next); - if (NextMustBeValue && (PreviousMustBeValue || - Previous->isOneOf(tok::r_square, tok::r_paren, -tok::plusplus, tok::minusminus))) + bool NextEndsTemplateExpr = + Next->is(TT_TemplateString) && Next->TokenText.startswith("}"); + if (NextMustBeValue && !NextEndsTemplateExpr && !PreviousStartsTemplateExpr && + (PreviousMustBeValue || + Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus, + tok::minusminus))) addUnwrappedLine(); if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next)) addUnwrappedLine(); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r318942 - clang-format: [JS] handle destructuring `of`.
Author: mprobst Date: Fri Nov 24 02:48:25 2017 New Revision: 318942 URL: http://llvm.org/viewvc/llvm-project?rev=318942&view=rev Log: clang-format: [JS] handle destructuring `of`. Summary: Previously, clang-format would drop a space character between `of` and then following (non-identifier) token if the preceding token was part of a destructuring assignment (`}` or `]`). Before: for (const [a, b] of[]) {} After: for (const [a, b] of []) {} Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D40411 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=318942&r1=318941&r2=318942&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Fri Nov 24 02:48:25 2017 @@ -2397,9 +2397,11 @@ bool TokenAnnotator::spaceRequiredBefore 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 - // (e.g. as "const x of y" in a for loop). + // (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.getIdentifierInfo() || + Left.Previous->isOneOf(tok::r_square, tok::r_brace && (!Left.Previous || !Left.Previous->is(tok::period))) return true; if (Left.isOneOf(tok::kw_for, Keywords.kw_as) && Left.Previous && Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318942&r1=318941&r2=318942&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Nov 24 02:48:25 2017 @@ -1110,6 +1110,10 @@ TEST_F(FormatTestJS, ForLoops) { "}"); verifyFormat("for (let {a, b} of x) {\n" "}"); + verifyFormat("for (let {a, b} of [x]) {\n" + "}"); + verifyFormat("for (let [a, b] of [x]) {\n" + "}"); verifyFormat("for (let {a, b} in x) {\n" "}"); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r318957 - clang-format: [JS] space between ! assert and in.
Author: mprobst Date: Fri Nov 24 09:04:40 2017 New Revision: 318957 URL: http://llvm.org/viewvc/llvm-project?rev=318957&view=rev Log: clang-format: [JS] space between ! assert and in. Summary: Before: x = y!in z; After: x = y! in z; Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D40433 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=318957&r1=318956&r2=318957&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Fri Nov 24 09:04:40 2017 @@ -2433,8 +2433,9 @@ bool TokenAnnotator::spaceRequiredBefore return false; if (Right.is(TT_JsNonNullAssertion)) return false; -if (Left.is(TT_JsNonNullAssertion) && Right.is(Keywords.kw_as)) - return true; // "x! as string" +if (Left.is(TT_JsNonNullAssertion) && +Right.isOneOf(Keywords.kw_as, Keywords.kw_in)) + return true; // "x! as string", "x! in y" } else if (Style.Language == FormatStyle::LK_Java) { if (Left.is(tok::r_square) && Right.is(tok::l_brace)) return true; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318957&r1=318956&r2=318957&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Nov 24 09:04:40 2017 @@ -1908,6 +1908,7 @@ TEST_F(FormatTestJS, CastSyntax) { verifyFormat("x = x as {a: string};"); verifyFormat("x = x as (string);"); verifyFormat("x = x! as (string);"); + verifyFormat("x = y! in z;"); verifyFormat("var x = something.someFunction() as\n" "something;", getGoogleJSStyleWithColumns(40)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r318958 - clang-format: [JS] do not wrap before yield.
Author: mprobst Date: Fri Nov 24 09:05:35 2017 New Revision: 318958 URL: http://llvm.org/viewvc/llvm-project?rev=318958&view=rev Log: clang-format: [JS] do not wrap before yield. Summary: The same rules apply as for `return`. Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D40431 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=318958&r1=318957&r2=318958&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Fri Nov 24 09:05:35 2017 @@ -2699,8 +2699,8 @@ bool TokenAnnotator::canBreakBefore(cons } else if (Style.Language == FormatStyle::LK_JavaScript) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && -NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break, -tok::kw_throw, Keywords.kw_interface, +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, Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318958&r1=318957&r2=318958&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Nov 24 09:05:35 2017 @@ -1123,6 +1123,7 @@ TEST_F(FormatTestJS, WrapRespectsAutomat // would change due to automatic semicolon insertion. // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1. verifyFormat("return a;", getGoogleJSStyleWithColumns(10)); + verifyFormat("yield a;", getGoogleJSStyleWithColumns(10)); verifyFormat("return /* hello! */ a;", getGoogleJSStyleWithColumns(10)); verifyFormat("continue a;", getGoogleJSStyleWithColumns(10)); verifyFormat("continue /* hello! */ a;", getGoogleJSStyleWithColumns(10)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r318959 - clang-format: [JS] do not break in ArrayType[].
Author: mprobst Date: Fri Nov 24 09:05:56 2017 New Revision: 318959 URL: http://llvm.org/viewvc/llvm-project?rev=318959&view=rev Log: clang-format: [JS] do not break in ArrayType[]. Summary: Wrapping between the type name and the array type indicator creates invalid syntax in TypeScript. Before: const xIsALongIdent: YJustBarelyFitsLinex []; // illegal syntax. After: const xIsALongIdent: YJustBarelyFitsLinex[]; Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D40436 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=318959&r1=318958&r2=318959&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Fri Nov 24 09:05:56 2017 @@ -2706,6 +2706,9 @@ bool TokenAnnotator::canBreakBefore(cons Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get, Keywords.kw_set)) return false; // Otherwise automatic semicolon insertion would trigger. +if (Left.Tok.getIdentifierInfo() && +Right.startsSequence(tok::l_square, tok::r_square)) + return false; // breaking in "foo[]" creates illegal TS type syntax. if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace)) return false; if (Left.is(TT_JsTypeColon)) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318959&r1=318958&r2=318959&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Nov 24 09:05:56 2017 @@ -1426,6 +1426,8 @@ TEST_F(FormatTestJS, TypeAnnotations) { verifyFormat( "var someValue = (v as [])\n" ".someFunction(aa);"); + verifyFormat("const xIsALongIdent:\n""YJustBarelyFitsLinex[];", + getGoogleJSStyleWithColumns(20)); } TEST_F(FormatTestJS, UnionIntersectionTypes) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r318973 - clang-format: [JS] disable ASI on decorators.
Author: mprobst Date: Sat Nov 25 01:19:42 2017 New Revision: 318973 URL: http://llvm.org/viewvc/llvm-project?rev=318973&view=rev Log: clang-format: [JS] disable ASI on decorators. Summary: 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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D40410 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=318973&r1=318972&r2=318973&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Sat Nov 25 01:19:42 2017 @@ -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 @@ void UnwrappedLineParser::readTokenWithJ 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) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318973&r1=318972&r2=318973&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sat Nov 25 01:19:42 2017 @@ -1197,6 +1197,8 @@ TEST_F(FormatTestJS, AutomaticSemicolonI "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, EnumDeclarations) { "}"); } -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}"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r318974 - clang-format: [JS] handle `for` as object label.
Author: mprobst Date: Sat Nov 25 01:24:33 2017 New Revision: 318974 URL: http://llvm.org/viewvc/llvm-project?rev=318974&view=rev Log: clang-format: [JS] handle `for` as object label. Summary: Previously, clang-format would fail formatting `{for: 1}`. Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D40441 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=318974&r1=318973&r2=318974&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Sat Nov 25 01:24:33 2017 @@ -617,7 +617,9 @@ private: break; case tok::kw_for: if (Style.Language == FormatStyle::LK_JavaScript) { -if (Tok->Previous && Tok->Previous->is(tok::period)) +// x.for and {for: ...} +if ((Tok->Previous && Tok->Previous->is(tok::period)) || +(Tok->Next && Tok->Next->is(tok::colon))) break; // JS' for await ( ... if (CurrentToken && CurrentToken->is(Keywords.kw_await)) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318974&r1=318973&r2=318974&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sat Nov 25 01:24:33 2017 @@ -323,6 +323,11 @@ TEST_F(FormatTestJS, ReservedWords) { " case: string;\n" " default: string;\n" "}\n"); + verifyFormat("const Axis = {\n" + " for: 'for',\n" + " x: 'x'\n" + "};", + "const Axis = {for: 'for', x: 'x'};"); } TEST_F(FormatTestJS, ReservedWordsMethods) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r318975 - clang-format: [JS] handle semis in generic types.
Author: mprobst Date: Sat Nov 25 01:33:47 2017 New Revision: 318975 URL: http://llvm.org/viewvc/llvm-project?rev=318975&view=rev Log: clang-format: [JS] handle semis in generic types. Summary: 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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D40424 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=318975&r1=318974&r2=318975&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Sat Nov 25 01:33:47 2017 @@ -379,13 +379,16 @@ void UnwrappedLineParser::calculateBrace 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. Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318975&r1=318974&r2=318975&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sat Nov 25 01:33:47 2017 @@ -1414,6 +1414,7 @@ TEST_F(FormatTestJS, TypeAnnotations) { 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
r318976 - clang-format: [JS] do not collapse short classes.
Author: mprobst Date: Sat Nov 25 01:35:33 2017 New Revision: 318976 URL: http://llvm.org/viewvc/llvm-project?rev=318976&view=rev Log: clang-format: [JS] do not collapse short classes. Summary: clang-format does not collapse short records, interfaces, unions, etc., but fails to do so if the record is preceded by certain modifiers (export, default, abstract, declare). This change skips over all modifiers, and thus handles all record definitions uniformly. Before: export class Foo { bar: string; } class Baz { bam: string; } After: export class Foo { bar: string; } class Baz { bam: string; } Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D40430 Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=318976&r1=318975&r2=318976&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Sat Nov 25 01:35:33 2017 @@ -517,8 +517,13 @@ private: } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) && !startsExternCBlock(Line)) { // We don't merge short records. -FormatToken *RecordTok = -Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First; +FormatToken *RecordTok = Line.First; +// Skip record modifiers. +while (RecordTok->Next && + RecordTok->isOneOf(tok::kw_typedef, tok::kw_export, + Keywords.kw_declare, Keywords.kw_abstract, + tok::kw_default)) + RecordTok = RecordTok->Next; if (RecordTok && RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct, Keywords.kw_interface)) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=318976&r1=318975&r2=318976&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sat Nov 25 01:35:33 2017 @@ -1674,9 +1674,15 @@ TEST_F(FormatTestJS, Modules) { " x: number;\n" " y: string;\n" "}"); - verifyFormat("export class X { y: number; }"); - verifyFormat("export abstract class X { y: number; }"); - verifyFormat("export default class X { y: number }"); + verifyFormat("export class X {\n" + " y: number;\n" + "}"); + verifyFormat("export abstract class X {\n" + " y: number;\n" + "}"); + verifyFormat("export default class X {\n" + " y: number\n" + "}"); verifyFormat("export default function() {\n return 1;\n}"); verifyFormat("export var x = 12;"); verifyFormat("class C {}\n" @@ -1698,7 +1704,9 @@ TEST_F(FormatTestJS, Modules) { "];"); verifyFormat("export default [];"); verifyFormat("export default () => {};"); - verifyFormat("export interface Foo { foo: number; }\n" + verifyFormat("export interface Foo {\n" + " foo: number;\n" + "}\n" "export class Bar {\n" " blah(): string {\n" "return this.blah;\n" ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r319415 - clang-format: [JS] do not wrap after async/await.
Author: mprobst Date: Thu Nov 30 02:25:17 2017 New Revision: 319415 URL: http://llvm.org/viewvc/llvm-project?rev=319415&view=rev Log: clang-format: [JS] do not wrap after async/await. Summary: Otherwise automatic semicolon insertion can trigger, i.e. wrapping produces invalid syntax. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D40642 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=319415&r1=319414&r2=319415&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Thu Nov 30 02:25:17 2017 @@ -2701,12 +2701,12 @@ bool TokenAnnotator::canBreakBefore(cons } 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)) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=319415&r1=319414&r2=319415&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Thu Nov 30 02:25:17 2017 @@ -1152,6 +1152,11 @@ TEST_F(FormatTestJS, WrapRespectsAutomat "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
r369916 - clang-format: [JS] handle `as const`.
Author: mprobst Date: Mon Aug 26 08:37:05 2019 New Revision: 369916 URL: http://llvm.org/viewvc/llvm-project?rev=369916&view=rev Log: clang-format: [JS] handle `as const`. Summary: 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`. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66736 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=369916&r1=369915&r2=369916&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Aug 26 08:37:05 2019 @@ -2746,6 +2746,10 @@ bool TokenAnnotator::spaceRequiredBefore 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 Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=369916&r1=369915&r2=369916&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Aug 26 08:37:05 2019 @@ -1479,6 +1479,9 @@ TEST_F(FormatTestJS, TypeAnnotations) { ".someFunction(aa);"); verifyFormat("const xIsALongIdent:\n""YJustBarelyFitsLinex[];", getGoogleJSStyleWithColumns(20)); + verifyFormat("const x = {\n" + " y: 1\n" + "} as const;"); } TEST_F(FormatTestJS, UnionIntersectionTypes) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r309695 - clang-format: [JS] handle object types in extends positions.
Author: mprobst Date: Tue Aug 1 08:46:10 2017 New Revision: 309695 URL: http://llvm.org/viewvc/llvm-project?rev=309695&view=rev Log: clang-format: [JS] handle object types in extends positions. Summary: 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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36131 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=309695&r1=309694&r2=309695&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Aug 1 08:46:10 2017 @@ -2341,7 +2341,8 @@ bool TokenAnnotator::spaceRequiredBefore 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 && Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=309695&r1=309694&r2=309695&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Tue Aug 1 08:46:10 2017 @@ -1970,6 +1970,17 @@ void UnwrappedLineParser::parseRecord(bo ((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(); Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=309695&r1=309694&r2=309695&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 1 08:46:10 2017 @@ -1400,6 +1400,17 @@ TEST_F(FormatTestJS, InterfaceDeclaratio "}"); } +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" ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r309697 - clang-format: [JS] support default imports.
Author: mprobst Date: Tue Aug 1 08:54:43 2017 New Revision: 309697 URL: http://llvm.org/viewvc/llvm-project?rev=309697&view=rev Log: clang-format: [JS] support default imports. Summary: Formerly, `import {default as X} from y;` would not be recognized as an import. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36132 Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp cfe/trunk/unittests/Format/SortImportsTestJS.cpp Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/SortJavaScriptImports.cpp?rev=309697&r1=309696&r2=309697&view=diff == --- cfe/trunk/lib/Format/SortJavaScriptImports.cpp (original) +++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp Tue Aug 1 08:54:43 2017 @@ -413,7 +413,7 @@ private: 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 @@ private: 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(); Modified: cfe/trunk/unittests/Format/SortImportsTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/SortImportsTestJS.cpp?rev=309697&r1=309696&r2=309697&view=diff == --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp (original) +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp Tue Aug 1 08:54:43 2017 @@ -300,6 +300,14 @@ TEST_F(SortImportsTestJS, SortMultiLine) "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
r309703 - clang-format: [JS] consistenly format enums.
Author: mprobst Date: Tue Aug 1 10:12:15 2017 New Revision: 309703 URL: http://llvm.org/viewvc/llvm-project?rev=309703&view=rev Log: clang-format: [JS] consistenly format enums. Summary: Previously, const enums would get formatted differently because the modifier was not recognized. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36144 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=309703&r1=309702&r2=309703&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Aug 1 10:12:15 2017 @@ -2517,7 +2517,9 @@ bool TokenAnnotator::mustBreakBefore(con 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; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=309703&r1=309702&r2=309703&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 1 10:12:15 2017 @@ -1425,6 +1425,14 @@ TEST_F(FormatTestJS, EnumDeclarations) { " 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
r309707 - clang-format: [JS] handle union types in arrow functions.
Author: mprobst Date: Tue Aug 1 10:19:32 2017 New Revision: 309707 URL: http://llvm.org/viewvc/llvm-project?rev=309707&view=rev Log: clang-format: [JS] handle union types in arrow functions. Summary: 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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36147 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=309707&r1=309706&r2=309707&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Aug 1 10:19:32 2017 @@ -533,6 +533,7 @@ private: 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; } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=309707&r1=309706&r2=309707&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 1 10:19:32 2017 @@ -988,6 +988,9 @@ TEST_F(FormatTestJS, ArrowFunctions) { ".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
r309710 - clang-format: [JS] whitespace between keywords and parenthesized expressions.
Author: mprobst Date: Tue Aug 1 10:22:15 2017 New Revision: 309710 URL: http://llvm.org/viewvc/llvm-project?rev=309710&view=rev Log: clang-format: [JS] whitespace between keywords and parenthesized expressions. Summary: `throw (...)` should have a whitespace following it, as do await and void. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36146 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=309710&r1=309709&r2=309710&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Aug 1 10:22:15 2017 @@ -2349,6 +2349,9 @@ bool TokenAnnotator::spaceRequiredBefore 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 Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=309710&r1=309709&r2=309710&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 1 10:22:15 2017 @@ -259,6 +259,15 @@ TEST_F(FormatTestJS, ReservedWordsMethod "}\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
r309712 - clang-format: [JS] prefer wrapping chains over empty literals.
Author: mprobst Date: Tue Aug 1 10:35:57 2017 New Revision: 309712 URL: http://llvm.org/viewvc/llvm-project?rev=309712&view=rev Log: clang-format: [JS] prefer wrapping chains over empty literals. Summary: E.g. don't wrap like this: (foo.bar.baz).and.bam(Blah.of({ })) But rather: (foo.bar.baz) .and.bam(Blah.of({})) Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36139 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=309712&r1=309711&r2=309712&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Aug 1 10:35:57 2017 @@ -2006,6 +2006,9 @@ unsigned TokenAnnotator::splitPenalty(co 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)) Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=309712&r1=309711&r2=309712&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 1 10:35:57 2017 @@ -841,6 +841,15 @@ TEST_F(FormatTestJS, FunctionLiterals) { } +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
r309713 - clang-format: [JS] no whitespace between typeof operator and l_paren.
Author: mprobst Date: Tue Aug 1 10:42:16 2017 New Revision: 309713 URL: http://llvm.org/viewvc/llvm-project?rev=309713&view=rev Log: clang-format: [JS] no whitespace between typeof operator and l_paren. Modified: cfe/trunk/lib/Format/FormatToken.h cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/FormatToken.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=309713&r1=309712&r2=309713&view=diff == --- cfe/trunk/lib/Format/FormatToken.h (original) +++ cfe/trunk/lib/Format/FormatToken.h Tue Aug 1 10:42:16 2017 @@ -644,6 +644,7 @@ struct AdditionalKeywords { kw_readonly = &IdentTable.get("readonly"); kw_set = &IdentTable.get("set"); kw_type = &IdentTable.get("type"); +kw_typeof = &IdentTable.get("typeof"); kw_var = &IdentTable.get("var"); kw_yield = &IdentTable.get("yield"); @@ -680,7 +681,7 @@ struct AdditionalKeywords { JsExtraKeywords = std::unordered_set( {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from, kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly, - kw_set, kw_type, kw_var, kw_yield, + kw_set, kw_type, kw_typeof, kw_var, kw_yield, // Keywords from the Java section. kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface}); } @@ -714,6 +715,7 @@ struct AdditionalKeywords { IdentifierInfo *kw_readonly; IdentifierInfo *kw_set; IdentifierInfo *kw_type; + IdentifierInfo *kw_typeof; IdentifierInfo *kw_var; IdentifierInfo *kw_yield; Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=309713&r1=309712&r2=309713&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Aug 1 10:42:16 2017 @@ -2353,7 +2353,7 @@ bool TokenAnnotator::spaceRequiredBefore Left.Tok.getIdentifierInfo()) return false; if (Right.is(tok::l_paren) && -Left.isOneOf(tok::kw_throw, Keywords.kw_await, tok::kw_void)) +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) || Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=309713&r1=309712&r2=309713&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 1 10:42:16 2017 @@ -263,6 +263,7 @@ TEST_F(FormatTestJS, ReservedWordsParent // All of these are statements using the keyword, not function calls. verifyFormat("throw (x + y);\n" "await (await x).y;\n" + "typeof (x) === 'string';\n" "void (0);\n" "delete (x.y);\n" "return (x);\n"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r310070 - clang-format: [JS] support fields with case/switch/default labels.
Author: mprobst Date: Fri Aug 4 10:07:15 2017 New Revision: 310070 URL: http://llvm.org/viewvc/llvm-project?rev=310070&view=rev Log: clang-format: [JS] support fields with case/switch/default labels. Summary: `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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36148 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=310070&r1=310069&r2=310070&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Fri Aug 4 10:07:15 2017 @@ -326,6 +326,11 @@ void UnwrappedLineParser::parseLevel(boo 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 @@ void UnwrappedLineParser::parseStructura 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: Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=310070&r1=310069&r2=310070&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Aug 4 10:07:15 2017 @@ -242,6 +242,12 @@ TEST_F(FormatTestJS, ReservedWords) { 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
r310365 - clang-format: [JS] handle single lines comments ending in `\\`.
Author: mprobst Date: Tue Aug 8 07:52:42 2017 New Revision: 310365 URL: http://llvm.org/viewvc/llvm-project?rev=310365&view=rev Log: clang-format: [JS] handle single lines comments ending in `\\`. Summary: Previously, clang-format would consider the following code line to be part of the comment and incorrectly format the rest of the file. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36159 Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.cpp?rev=310365&r1=310364&r2=310365&view=diff == --- cfe/trunk/lib/Format/FormatTokenLexer.cpp (original) +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp Tue Aug 8 07:52:42 2017 @@ -529,6 +529,34 @@ FormatToken *FormatTokenLexer::getNextTo 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. Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=310365&r1=310364&r2=310365&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 8 07:52:42 2017 @@ -2074,5 +2074,27 @@ TEST_F(FormatTestJS, NestedLiterals) { "};", 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 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r310367 - clang-format: [JS] fix union type spacing in object & array types.
Author: mprobst Date: Tue Aug 8 08:00:58 2017 New Revision: 310367 URL: http://llvm.org/viewvc/llvm-project?rev=310367&view=rev Log: clang-format: [JS] fix union type spacing in object & array types. Summary: Previously, clang-format would insert whitespace in union types nested in object and array types, as it wouldn't recognize those as a type operator: const x: {foo: number | null}; const x: [number | null]; While this is correct for actual binary operators, clang-format should not insert whitespace into union and intersection types to mark those: const x: {foo: number|null}; const x: [number|null]; This change propagates that the context is not an expression by inspecting the preceding token and marking as non-expression if it was a type colon. Reviewers: djasper Subscribers: klimek Differential Revision: https://reviews.llvm.org/D36136 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=310367&r1=310366&r2=310367&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Aug 8 08:00:58 2017 @@ -372,6 +372,10 @@ private: ScopedContextCreator ContextCreator(*this, tok::l_square, BindingIncrease); Contexts.back().IsExpression = true; +if (Style.Language == FormatStyle::LK_JavaScript && Parent && +Parent->is(TT_JsTypeColon)) + Contexts.back().IsExpression = false; + Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr; while (CurrentToken) { @@ -439,6 +443,9 @@ private: Contexts.back().ColonIsDictLiteral = true; if (Left->BlockKind == BK_BracedInit) Contexts.back().IsExpression = true; + if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && + Left->Previous->is(TT_JsTypeColon)) +Contexts.back().IsExpression = false; while (CurrentToken) { if (CurrentToken->is(tok::r_brace)) { @@ -531,6 +538,8 @@ private: !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) || Contexts.back().ContextKind == tok::l_paren || // function params Contexts.back().ContextKind == tok::l_square || // array type +(!Contexts.back().IsExpression && + Contexts.back().ContextKind == tok::l_brace) || // object type (Contexts.size() == 1 && Line.MustBeDeclaration)) { // method/property declaration Contexts.back().IsExpression = false; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=310367&r1=310366&r2=310367&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Aug 8 08:00:58 2017 @@ -1363,6 +1363,18 @@ TEST_F(FormatTestJS, UnionIntersectionTy "};"); } +TEST_F(FormatTestJS, UnionIntersectionTypesInObjectType) { + verifyFormat("let x: {x: number|null} = {x: number | null};"); + verifyFormat("let nested: {x: {y: number|null}};"); + verifyFormat("let mixed: {x: [number|null, {w: number}]};"); + verifyFormat("class X {\n" + " contructor(x: {\n" + "a: a|null,\n" + "b: b|null,\n" + " }) {}\n" + "}"); +} + TEST_F(FormatTestJS, ClassDeclarations) { verifyFormat("class C {\n x: string = 12;\n}"); verifyFormat("class C {\n x(): string => 12;\n}"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r310482 - clang-format: [JS] detect ASI after closing parens.
Author: mprobst Date: Wed Aug 9 08:19:16 2017 New Revision: 310482 URL: http://llvm.org/viewvc/llvm-project?rev=310482&view=rev Log: clang-format: [JS] detect ASI after closing parens. Summary: A closing parenthesis followed by a declaration or statement should always terminate the current statement. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36491 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=310482&r1=310481&r2=310482&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Wed Aug 9 08:19:16 2017 @@ -853,7 +853,8 @@ void UnwrappedLineParser::readTokenWithJ 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(); } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=310482&r1=310481&r2=310482&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Wed Aug 9 08:19:16 2017 @@ -1106,6 +1106,10 @@ TEST_F(FormatTestJS, WrapRespectsAutomat " 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
r310851 - clang-format: [JS] do not insert whitespace in call positions.
Author: mprobst Date: Mon Aug 14 09:08:16 2017 New Revision: 310851 URL: http://llvm.org/viewvc/llvm-project?rev=310851&view=rev Log: clang-format: [JS] do not insert whitespace in call positions. Summary: 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. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D36142 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=310851&r1=310850&r2=310851&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Aug 14 09:08:16 2017 @@ -2367,13 +2367,20 @@ bool TokenAnnotator::spaceRequiredBefore 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 Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=310851&r1=310850&r2=310851&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Aug 14 09:08:16 2017 @@ -271,14 +271,21 @@ TEST_F(FormatTestJS, ReservedWords) { 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 @@ TEST_F(FormatTestJS, TryCatch) { // 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) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r310852 - clang-format: [JS] wrap optional properties in type aliases.
Author: mprobst Date: Mon Aug 14 09:09:08 2017 New Revision: 310852 URL: http://llvm.org/viewvc/llvm-project?rev=310852&view=rev Log: clang-format: [JS] wrap optional properties in type aliases. Summary: 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, }; Reviewers: djasper, sammccall Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D36684 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=310852&r1=310851&r2=310852&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Aug 14 09:09:08 2017 @@ -459,6 +459,8 @@ private: 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 @@ private: 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 Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=310852&r1=310851&r2=310852&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Aug 14 09:09:08 2017 @@ -1561,6 +1561,10 @@ TEST_F(FormatTestJS, TypeAliases) { " 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
[clang] 736a380 - clang-format: [JS] tests for async wrapping.
Author: Martin Probst Date: 2020-01-16T11:23:11+01:00 New Revision: 736a3802124b57490fa1e67538415a2a77fa731c URL: https://github.com/llvm/llvm-project/commit/736a3802124b57490fa1e67538415a2a77fa731c DIFF: https://github.com/llvm/llvm-project/commit/736a3802124b57490fa1e67538415a2a77fa731c.diff LOG: clang-format: [JS] tests for async wrapping. Summary: Adds tests to ensure that `async method() ...` does not wrap between async and the method name, which would cause automatic semicolon insertion. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D70377 Added: Modified: clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 619a19f1a22d..f5be0d7a4ab1 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -737,6 +737,22 @@ TEST_F(FormatTestJS, AsyncFunctions) { " 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
[clang] 16212b8 - clang-format: [JS] support new assignment operators.
Author: Martin Probst Date: 2020-11-10T09:26:46+01:00 New Revision: 16212b8b3e4fd5fbb73aecabf6f0b6fec91913d2 URL: https://github.com/llvm/llvm-project/commit/16212b8b3e4fd5fbb73aecabf6f0b6fec91913d2 DIFF: https://github.com/llvm/llvm-project/commit/16212b8b3e4fd5fbb73aecabf6f0b6fec91913d2.diff LOG: clang-format: [JS] support new assignment operators. Before: a && = b; After: a &&= b; These operators are new additions in ES2021. Differential Revision: https://reviews.llvm.org/D91132 Added: Modified: clang/lib/Format/FormatToken.h clang/lib/Format/FormatTokenLexer.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index a3cb81f1b1ef..d53c016fd4db 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -68,6 +68,9 @@ namespace format { TYPE(JsTypeColon) \ TYPE(JsTypeOperator) \ TYPE(JsTypeOptionalQuestion) \ + TYPE(JsAndAndEqual) \ + TYPE(JsPipePipeEqual) \ + TYPE(JsNullishCoalescingEqual) \ TYPE(LambdaArrow) \ TYPE(LambdaLBrace) \ TYPE(LambdaLSquare) \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 2415da3a7ffb..8733834a079a 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -121,6 +121,10 @@ void FormatTokenLexer::tryMergePreviousTokens() { 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 @@ void FormatTokenLexer::tryMergePreviousTokens() { 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; } diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index d140fe581f2a..84d76c67764a 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -2424,6 +2424,15 @@ TEST_F(FormatTestJS, NullishCoalescingOperator) { 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;"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 63042d4 - clang-format: [JS] don't sort named imports if off.
Author: Martin Probst Date: 2021-06-11T12:02:33+02:00 New Revision: 63042d46bb0c2481a8b7aa1c324405c2720b3603 URL: https://github.com/llvm/llvm-project/commit/63042d46bb0c2481a8b7aa1c324405c2720b3603 DIFF: https://github.com/llvm/llvm-project/commit/63042d46bb0c2481a8b7aa1c324405c2720b3603.diff LOG: clang-format: [JS] don't sort named imports if off. The previous implementation would accidentally still sort the individual named imports, even if the module reference was in a clang-format off block. Differential Revision: https://reviews.llvm.org/D104101 Added: Modified: clang/lib/Format/SortJavaScriptImports.cpp clang/unittests/Format/SortImportsTestJS.cpp Removed: diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp index 4b88ece02a109..901204c297f9d 100644 --- a/clang/lib/Format/SortJavaScriptImports.cpp +++ b/clang/lib/Format/SortJavaScriptImports.cpp @@ -317,6 +317,11 @@ class JavaScriptImportSorter : public TokenAnalyzer { // 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; diff --git a/clang/unittests/Format/SortImportsTestJS.cpp b/clang/unittests/Format/SortImportsTestJS.cpp index 031dadaaa7a22..4b426375cfea8 100644 --- a/clang/unittests/Format/SortImportsTestJS.cpp +++ b/clang/unittests/Format/SortImportsTestJS.cpp @@ -431,6 +431,17 @@ TEST_F(SortImportsTestJS, RespectsClangFormatOff) { "// 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 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] a7638d3 - clang-format: [JS] support null operators.
Author: Martin Probst Date: 2019-11-11T16:35:35+01:00 New Revision: a7638d384983e8e3eb44a2d8c757238efc7096dc URL: https://github.com/llvm/llvm-project/commit/a7638d384983e8e3eb44a2d8c757238efc7096dc DIFF: https://github.com/llvm/llvm-project/commit/a7638d384983e8e3eb44a2d8c757238efc7096dc.diff LOG: clang-format: [JS] support null operators. Summary: JavaScript / TypeScript is adding two new operators: the null propagating operator `?.` and the nullish coalescing operator `??`. const x = foo ?? 'default'; const z = foo?.bar?.baz; This change adds support to lex and format both. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D69971 Added: Modified: clang/lib/Format/FormatToken.h clang/lib/Format/FormatTokenLexer.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index b11f36559a8b..39498280fb6d 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -60,6 +60,8 @@ namespace format { TYPE(JsExponentiationEqual) \ TYPE(JsFatArrow) \ TYPE(JsNonNullAssertion) \ + TYPE(JsNullishCoalescingOperator) \ + TYPE(JsNullPropagatingOperator) \ TYPE(JsPrivateIdentifier) \ TYPE(JsTypeColon) \ TYPE(JsTypeOperator) \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 5d8a77577c0b..ef20ba884fb3 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -100,6 +100,10 @@ void FormatTokenLexer::tryMergePreviousTokens() { static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star}; static const tok::TokenKind JSExponentiationEqual[] = {tok::star, tok::starequal}; +static const tok::TokenKind JSNullPropagatingOperator[] = {tok::question, + tok::period}; +static const tok::TokenKind JSNullishOperator[] = {tok::question, + tok::question}; // FIXME: Investigate what token type gives the correct operator priority. if (tryMergeTokens(JSIdentity, TT_BinaryOperator)) @@ -116,6 +120,14 @@ void FormatTokenLexer::tryMergePreviousTokens() { Tokens.back()->Tok.setKind(tok::starequal); return; } +if (tryMergeTokens(JSNullishOperator, TT_JsNullishCoalescingOperator)) + return; +if (tryMergeTokens(JSNullPropagatingOperator, + TT_JsNullPropagatingOperator)) { + // Treat like a regular "." access. + Tokens.back()->Tok.setKind(tok::period); + return; +} if (tryMergeJSPrivateIdentifier()) return; } diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index ca2093a05cce..30a0b37ef69b 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -,6 +,16 @@ TEST_F(FormatTestJS, NonNullAssertionOperator) { verifyFormat("return !!x;\n"); } +TEST_F(FormatTestJS, NullPropagatingOperator) { + verifyFormat("let x = foo?.bar?.baz();\n"); + verifyFormat("let x = foo?.(foo);\n"); + verifyFormat("let x = foo?.['arr'];\n"); +} + +TEST_F(FormatTestJS, NullishCoalescingOperator) { + verifyFormat("const val = something ?? 'some other default';\n"); +} + TEST_F(FormatTestJS, Conditional) { verifyFormat("y = x ? 1 : 2;"); verifyFormat("x ? 1 : 2;"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6bcd8d4 - clang-format: [JS] test declared fields.
Author: Martin Probst Date: 2019-11-11T16:36:00+01:00 New Revision: 6bcd8d4a18fc0604a2297a626c1fc808cbfb7b9b URL: https://github.com/llvm/llvm-project/commit/6bcd8d4a18fc0604a2297a626c1fc808cbfb7b9b DIFF: https://github.com/llvm/llvm-project/commit/6bcd8d4a18fc0604a2297a626c1fc808cbfb7b9b.diff LOG: clang-format: [JS] test declared fields. Summary: TypeScript now supports declaring fields: class Foo { declare field: string; } clang-format happens to already format this fine, so this change just adds a regression test. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D69972 Added: Modified: clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 30a0b37ef69b..619a19f1a22d 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -2369,5 +2369,12 @@ TEST_F(FormatTestJS, SupportPrivateFieldsAndMethods) { " static #staticPrivateMethod() {}\n"); } +TEST_F(FormatTestJS, DeclaredFields) { + verifyFormat("class Example {\n" + " declare pub: string;\n" + " declare private priv: string;\n" + "}\n"); +} + } // namespace format } // end namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] dc04c54 - clang-format: [JS] document InsertTrailingCommas.
Author: Martin Probst Date: 2020-02-03T08:51:52+01:00 New Revision: dc04c54fc1f6660770040f9a17ea600ce95e4b60 URL: https://github.com/llvm/llvm-project/commit/dc04c54fc1f6660770040f9a17ea600ce95e4b60 DIFF: https://github.com/llvm/llvm-project/commit/dc04c54fc1f6660770040f9a17ea600ce95e4b60.diff LOG: clang-format: [JS] document InsertTrailingCommas. Summary: In release notes and the regular docs. Reviewers: MyDeveloperDay Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D73768 Added: Modified: clang/docs/ClangFormatStyleOptions.rst clang/docs/ReleaseNotes.rst Removed: diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 981542451b29..0c515922e650 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -717,6 +717,26 @@ the configuration (without a prefix: ``Auto``). aaa); } + +**InsertTrailingCommas** (``TrailingCommaStyle``) can be set to ``TCS_Wrapped`` + to insert trailing commas in container literals (arrays and objects) that wrap + across multiple lines. It is currently only available for JavaScript and + disabled by default (``TCS_None``). + + ``InsertTrailingCommas`` cannot be used together with ``BinPackArguments`` as + inserting the comma disables bin-packing. + + .. code-block:: c++ + +TSC_Wrapped: +const someArray = [ + aa, + aa, + aa, + //^ inserted +] + + **BinPackParameters** (``bool``) If ``false``, a function declaration's or function definition's parameters will either all be on the same line or will have one line each. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index eae0dfb12151..cb8d73932bf6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -175,6 +175,11 @@ clang-format } } +- Option ``InsertTrailingCommas`` can be set to ``TCS_Wrapped`` to insert + trailing commas in container literals (arrays and objects) that wrap across + multiple lines. It is currently only available for JavaScript and disabled by + default (``TCS_None``). + libclang ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 0734fb2 - clang-format: [JS] Handle more keyword-named methods.
Author: Martin Probst Date: 2020-01-17T10:10:16+01:00 New Revision: 0734fb21ed5e267dda1a91e5f8b82f653ac3562d URL: https://github.com/llvm/llvm-project/commit/0734fb21ed5e267dda1a91e5f8b82f653ac3562d DIFF: https://github.com/llvm/llvm-project/commit/0734fb21ed5e267dda1a91e5f8b82f653ac3562d.diff LOG: clang-format: [JS] Handle more keyword-named methods. Summary: Including `do`, `for`, and `while`, `if`, `else`, `try`, `catch`, in addition to the previously handled fields. The unit test explicitly uses methods, but this code path handles both fields and methods. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D72827 Added: Modified: clang/lib/Format/UnwrappedLineParser.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index ead6b4743207..18b4cc5306f5 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1011,13 +1011,22 @@ void UnwrappedLineParser::parseStructuralElement() { parseAccessSpecifier(); return; case tok::kw_if: +if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration) + // field/method declaration. + break; parseIfThenElse(); 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: @@ -1045,6 +1054,9 @@ void UnwrappedLineParser::parseStructuralElement() { return; case tok::kw_try: case tok::kw___try: +if (Style.Language == FormatStyle::LK_JavaScript && Line->MustBeDeclaration) + // field/method declaration. + break; parseTryCatch(); return; case tok::kw_extern: @@ -1290,6 +1302,12 @@ void UnwrappedLineParser::parseStructuralElement() { // element continues. break; case tok::kw_try: + if (Style.Language == FormatStyle::LK_JavaScript && + Line->MustBeDeclaration) { +// field/method declaration. +nextToken(); +break; + } // We arrive here when parsing function-try blocks. if (Style.BraceWrapping.AfterFunction) addUnwrappedLine(); diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index f5be0d7a4ab1..0150b43a0787 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -358,6 +358,22 @@ TEST_F(FormatTestJS, ReservedWordsMethods) { "x();\n" " }\n" "}\n"); + verifyFormat("class KeywordNamedMethods {\n" + " do() {\n" + " }\n" + " for() {\n" + " }\n" + " while() {\n" + " }\n" + " if() {\n" + " }\n" + " else() {\n" + " }\n" + " try() {\n" + " }\n" + " catch() {\n" + " }\n" + "}\n"); } TEST_F(FormatTestJS, ReservedWordsParenthesized) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9835cf1 - clang-format: [JS] pragmas for tslint, tsc.
Author: Martin Probst Date: 2020-01-17T13:39:05+01:00 New Revision: 9835cf159014f40e8ea655d0bb3a341ef7ec34f7 URL: https://github.com/llvm/llvm-project/commit/9835cf159014f40e8ea655d0bb3a341ef7ec34f7 DIFF: https://github.com/llvm/llvm-project/commit/9835cf159014f40e8ea655d0bb3a341ef7ec34f7.diff LOG: clang-format: [JS] pragmas for tslint, tsc. Summary: tslint and tsc (the TypeScript compiler itself) use comment pragmas of the style: // tslint:disable-next-line:foo // @ts-ignore These must not be wrapped and must stay on their own line, in isolation. For tslint, this required adding it to the pragma regexp. The comments starting with `@` are already left alone, but this change adds test coverage for them. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D72907 Added: Modified: clang/lib/Format/Format.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index f12bca48c630..cce9458cf22f 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -939,9 +939,9 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; -// taze:, triple slash directives (`/// <...`), @see, which is commonly -// followed by overlong URLs. -GoogleStyle.CommentPragmas = "(taze:|^/[ \t]*<|@see)"; +// taze:, triple slash directives (`/// <...`), tslint:, and @see, which is +// commonly followed by overlong URLs. +GoogleStyle.CommentPragmas = "(taze:|^/[ \t]*<|tslint:|@see)"; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 0150b43a0787..ffeb53d9a33c 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -2168,6 +2168,38 @@ TEST_F(FormatTestJS, JSDocAnnotations) { getGoogleJSStyleWithColumns(20))); } +TEST_F(FormatTestJS, TslintComments) { + // tslint uses pragma comments that must be on their own line. + verifyFormat("// Comment that needs wrapping. Comment that needs wrapping. " + "Comment that needs\n" + "// wrapping. Trailing line.\n" + "// tslint:disable-next-line:must-be-on-own-line", + "// Comment that needs wrapping. Comment that needs wrapping. " + "Comment that needs wrapping.\n" + "// Trailing line.\n" + "// tslint:disable-next-line:must-be-on-own-line"); +} + +TEST_F(FormatTestJS, TscComments) { + // As above, @ts-ignore and @ts-check comments must be on their own line. + verifyFormat("// Comment that needs wrapping. Comment that needs wrapping. " + "Comment that needs\n" + "// wrapping. Trailing line.\n" + "// @ts-ignore", + "// Comment that needs wrapping. Comment that needs wrapping. " + "Comment that needs wrapping.\n" + "// Trailing line.\n" + "// @ts-ignore"); + verifyFormat("// Comment that needs wrapping. Comment that needs wrapping. " + "Comment that needs\n" + "// wrapping. Trailing line.\n" + "// @ts-check", + "// Comment that needs wrapping. Comment that needs wrapping. " + "Comment that needs wrapping.\n" + "// Trailing line.\n" + "// @ts-check"); +} + TEST_F(FormatTestJS, RequoteStringsSingle) { verifyFormat("var x = 'foo';", "var x = \"foo\";"); verifyFormat("var x = 'fo\\'o\\'';", "var x = \"fo'o'\";"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 4c9d691 - clang-format: [JS] fix `??` opreator wrapping.
Author: Martin Probst Date: 2020-01-20T17:07:14+01:00 New Revision: 4c9d6914453d970b7b8202b7efd7524b2f0a72ac URL: https://github.com/llvm/llvm-project/commit/4c9d6914453d970b7b8202b7efd7524b2f0a72ac DIFF: https://github.com/llvm/llvm-project/commit/4c9d6914453d970b7b8202b7efd7524b2f0a72ac.diff LOG: clang-format: [JS] fix `??` opreator wrapping. Summary: clang-format currently treats the nullish coalescing operator `??` like the ternary operator. That causes multiple nullish terms to be each indented relative to the last `??`, as they would in a ternary. The `??` operator is often used in chains though, and as such more similar to other binary operators, such as `||`. So to fix the indent, set its token type to `||`, so it inherits the same treatment. This opens up the question of operator precedence. However, `??` is required to be parenthesized when mixed with `||` and `&&`, so this is not a problem that can come up in syntactically legal code. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D73026 Added: Modified: clang/lib/Format/FormatTokenLexer.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index ef20ba884fb3..9c9fee2b0c32 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -120,8 +120,11 @@ void FormatTokenLexer::tryMergePreviousTokens() { Tokens.back()->Tok.setKind(tok::starequal); return; } -if (tryMergeTokens(JSNullishOperator, TT_JsNullishCoalescingOperator)) +if (tryMergeTokens(JSNullishOperator, TT_JsNullishCoalescingOperator)) { + // Treat like the "||" operator (as opposed to the ternary ?). + Tokens.back()->Tok.setKind(tok::pipepipe); return; +} if (tryMergeTokens(JSNullPropagatingOperator, TT_JsNullPropagatingOperator)) { // Treat like a regular "." access. diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index ffeb53d9a33c..ef3c6361355a 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -2294,6 +2294,11 @@ TEST_F(FormatTestJS, NullPropagatingOperator) { TEST_F(FormatTestJS, NullishCoalescingOperator) { verifyFormat("const val = something ?? 'some other default';\n"); + verifyFormat( + "const val = something ?? otherDefault ??\n" + "evenMore ?? evenMore;\n", + "const val = something ?? otherDefault ?? evenMore ?? evenMore;\n", + getGoogleJSStyleWithColumns(40)); } TEST_F(FormatTestJS, Conditional) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 02656f2 - clang-format: [JS] options for arrow functions.
Author: Martin Probst Date: 2020-01-27T16:27:25+01:00 New Revision: 02656f29abda4eedd22e3b2b30bf2f422983514e URL: https://github.com/llvm/llvm-project/commit/02656f29abda4eedd22e3b2b30bf2f422983514e DIFF: https://github.com/llvm/llvm-project/commit/02656f29abda4eedd22e3b2b30bf2f422983514e.diff LOG: clang-format: [JS] options for arrow functions. Summary: clang-format currently always wraps the body of non-empty arrow functions: const x = () => { z(); }; This change implements support for the `AllowShortLambdasOnASingleLine` style options, controlling the indent style for arrow function bodies that have one or fewer statements. SLS_All puts all on a single line, SLS_Inline only arrow functions used in an inline position. const x = () => { z(); }; Multi-statement arrow functions continue to be wrapped. Function expressions (`a = function() {}`) and function/method declarations are unaffected as well. Reviewers: krasimir Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D73335 Added: Modified: clang/lib/Format/Format.cpp clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index a962e32f66b0..bc9551756bee 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -939,6 +939,8 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; GoogleStyle.AlignOperands = false; GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; +// TODO: still under discussion whether to switch to SLS_All. +GoogleStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.BreakBeforeTernaryOperators = false; // taze:, triple slash directives (`/// <...`), tslint:, and @see, which is diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 723dc5c7ba88..8f9a29ab2f29 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3144,6 +3144,26 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // JavaScript top-level enum key/value pairs are put on separate lines // instead of bin-packing. return true; +if (Right.is(tok::r_brace) && Left.is(tok::l_brace) && Left.Previous && +Left.Previous->is(TT_JsFatArrow)) { + // JS arrow function (=> {...}). + switch (Style.AllowShortLambdasOnASingleLine) { + case FormatStyle::SLS_All: +return false; + case FormatStyle::SLS_None: +return true; + case FormatStyle::SLS_Empty: +return !Left.Children.empty(); + case FormatStyle::SLS_Inline: +// allow one-lining inline (e.g. in function call args) and empty arrow +// functions. +return (Left.NestingLevel == 0 && Line.Level == 0) && + !Left.Children.empty(); + default: +break; + } +} + if (Right.is(tok::r_brace) && Left.is(tok::l_brace) && !Left.Children.empty()) // Support AllowShortFunctionsOnASingleLine for JavaScript. diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index ef3c6361355a..3c104b7aadbe 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -459,8 +459,9 @@ TEST_F(FormatTestJS, ContainerLiterals) { // Arrow functions in object literals. verifyFormat("var x = {\n" " y: (a) => {\n" + "x();\n" "return a;\n" - " }\n" + " },\n" "};"); verifyFormat("var x = {y: (a) => a};"); @@ -486,7 +487,8 @@ TEST_F(FormatTestJS, ContainerLiterals) { // Object literals can leave out labels. verifyFormat("f({a}, () => {\n" - " g(); //\n" + " x;\n" + " g();\n" "});"); // Keys can be quoted. @@ -1112,8 +1114,9 @@ TEST_F(FormatTestJS, MultipleFunctionLiterals) { TEST_F(FormatTestJS, ArrowFunctions) { verifyFormat("var x = (a) => {\n" + " x;\n" " return a;\n" - "};"); + "};\n"); verifyFormat("var x = (a) => {\n" " function y() {\n" "return 42;\n" @@ -1121,6 +1124,7 @@ TEST_F(FormatTestJS, ArrowFunctions) { " return a;\n" "};"); verifyFormat("var x = (a: type): {some: type} => {\n" + " y;\n" " return a;\n" "};"); verifyFormat("var x = (a) => a;"); @@ -1147,10 +1151,41 @@ TEST_F(FormatTestJS, ArrowFunctions) { "// break\n"
[clang] a324fcf - clang-format: insert trailing commas into containers.
Author: Martin Probst Date: 2020-01-29T13:23:54+01:00 New Revision: a324fcf1ae62d065b957e66a9d2f5c18b6259d27 URL: https://github.com/llvm/llvm-project/commit/a324fcf1ae62d065b957e66a9d2f5c18b6259d27 DIFF: https://github.com/llvm/llvm-project/commit/a324fcf1ae62d065b957e66a9d2f5c18b6259d27.diff LOG: clang-format: insert trailing commas into containers. Summary: This change adds an option to insert trailing commas into container literals. For example, in JavaScript: const x = [ a, b, ^ inserted if missing. ] This is implemented as a seperate post-processing pass after formatting (because formatting might change whether the container literal does or does not wrap). This keeps the code relatively simple and orthogonal, though it has the notable drawback that the newly inserted comma is not taken into account for formatting decisions (e.g. it might exceed the 80 char limit). To avoid exceeding the ColumnLimit, a comma is only inserted if it fits into the limit. Trailing comma insertion conceptually conflicts with argument bin-packing: inserting a comma disables bin-packing, so we cannot do both. clang-format rejects FormatStyle configurations that do both with this change. Reviewers: krasimir, MyDeveloperDay Subscribers: cfe-commits Tags: #clang Added: Modified: clang/include/clang/Format/Format.h clang/lib/Format/Format.cpp clang/unittests/Format/FormatTest.cpp clang/unittests/Format/FormatTestJS.cpp Removed: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 09a0556ab4c6..3891029a6f3a 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -35,7 +35,12 @@ class DiagnosticConsumer; namespace format { -enum class ParseError { Success = 0, Error, Unsuitable }; +enum class ParseError { + Success = 0, + Error, + Unsuitable, + BinPackTrailingCommaConflict +}; class ParseErrorCategory final : public std::error_category { public: const char *name() const noexcept override; @@ -544,6 +549,20 @@ struct FormatStyle { /// \endcode bool BinPackArguments; + /// The style of inserting trailing commas into container literals. + enum TrailingCommaStyle { +/// Do not insert trailing commas. +TCS_None, +/// Insert trailing commas in container literals that were wrapped over +/// multiple lines. Note that this is conceptually incompatible with +/// bin-packing, because the trailing comma is used as an indicator +/// that a container should be formatted one-per-line (i.e. not bin-packed). +/// So inserting a trailing comma counteracts bin-packing. +TCS_Wrapped, + }; + + TrailingCommaStyle InsertTrailingCommas; + /// If ``false``, a function declaration's or function definition's /// parameters will either all be on the same line or will have one line each. /// \code diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index dd131a93362c..6f585ae915a5 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -157,6 +157,13 @@ template <> struct ScalarEnumerationTraits { } }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) { +IO.enumCase(Value, "None", FormatStyle::TCS_None); +IO.enumCase(Value, "Wrapped", FormatStyle::TCS_Wrapped); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) { IO.enumCase(Value, "All", FormatStyle::BOS_All); @@ -486,6 +493,7 @@ template <> struct MappingTraits { IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("IndentWrappedFunctionNames", Style.IndentWrappedFunctionNames); +IO.mapOptional("InsertTrailingCommas", Style.InsertTrailingCommas); IO.mapOptional("JavaImportGroups", Style.JavaImportGroups); IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports); @@ -644,6 +652,8 @@ std::string ParseErrorCategory::message(int EV) const { return "Invalid argument"; case ParseError::Unsuitable: return "Unsuitable"; + case ParseError::BinPackTrailingCommaConflict: +return "trailing comma insertion cannot be used with bin packing"; } llvm_unreachable("unexpected parse error"); } @@ -788,6 +798,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentWrappedFunctionNames = false; LLVMStyle.IndentWidth = 2; + LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None; LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave; LLVMStyle.JavaScriptWrapImports = true; LLVMStyle.TabWidth = 8; @@ -946,6 +957,9 @@ FormatStyle getGoogleStyle(FormatStyle::Langua
r318537 - clang-format: remove trailing lines in lamdas and arrow functions.
Author: mprobst Date: Fri Nov 17 10:06:33 2017 New Revision: 318537 URL: http://llvm.org/viewvc/llvm-project?rev=318537&view=rev Log: clang-format: remove trailing lines in lamdas and arrow functions. Summary: clang-format already removes empty lines at the beginning & end of blocks: int x() { foo(); // lines before and after will be removed. } However because lamdas and arrow functions are parsed as expressions, the existing logic to remove empty lines in UnwrappedLineFormatter doesn't handle them. This change special cases arrow functions in ContinuationIndenter to remove empty lines: x = []() { foo(); // lines before and after will now be removed. }; Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D40178 Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp cfe/trunk/unittests/Format/FormatTest.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=318537&r1=318536&r2=318537&view=diff == --- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original) +++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Fri Nov 17 10:06:33 2017 @@ -701,8 +701,18 @@ unsigned ContinuationIndenter::addTokenO State.Stack.back().BreakBeforeParameter = false; if (!DryRun) { +unsigned MaxEmptyLinesToKeep = Style.MaxEmptyLinesToKeep + 1; +if (Current.is(tok::r_brace) && Current.MatchingParen && +// Only strip trailing empty lines for l_braces that have children, i.e. +// for function expressions (lambdas, arrows, etc). +!Current.MatchingParen->Children.empty()) { + // lambdas and arrow functions are expressions, thus their r_brace is not + // on its own line, and thus not covered by UnwrappedLineFormatter's logic + // about removing empty lines on closing blocks. Special case them here. + MaxEmptyLinesToKeep = 1; +} unsigned Newlines = std::max( -1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1)); +1u, std::min(Current.NewlinesBefore, MaxEmptyLinesToKeep)); bool ContinuePPDirective = State.Line->InPPDirective && State.Line->Type != LT_ImportStatement; Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column, Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=318537&r1=318536&r2=318537&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Fri Nov 17 10:06:33 2017 @@ -1117,6 +1117,9 @@ void UnwrappedLineFormatter::formatFirst (!RootToken.Next || (RootToken.Next->is(tok::semi) && !RootToken.Next->Next))) Newlines = std::min(Newlines, 1u); + // Remove empty lines at the start of nested blocks (lambdas/arrow functions) + if (PreviousLine == nullptr && Line.Level > 0) +Newlines = std::min(Newlines, 1u); if (Newlines == 0 && !RootToken.IsFirst) Newlines = 1; if (RootToken.IsFirst && !RootToken.HasUnescapedNewline) Modified: cfe/trunk/unittests/Format/FormatTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=318537&r1=318536&r2=318537&view=diff == --- cfe/trunk/unittests/Format/FormatTest.cpp (original) +++ cfe/trunk/unittests/Format/FormatTest.cpp Fri Nov 17 10:06:33 2017 @@ -70,18 +70,23 @@ protected: return getStyleWithColumns(getGoogleStyle(), ColumnLimit); } - void verifyFormat(llvm::StringRef Code, + void verifyFormat(llvm::StringRef Expected, llvm::StringRef Code, const FormatStyle &Style = getLLVMStyle()) { -EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); +EXPECT_EQ(Expected.str(), format(Code, Style)); if (Style.Language == FormatStyle::LK_Cpp) { // Objective-C++ is a superset of C++, so everything checked for C++ // needs to be checked for Objective-C++ as well. FormatStyle ObjCStyle = Style; ObjCStyle.Language = FormatStyle::LK_ObjC; - EXPECT_EQ(Code.str(), format(test::messUp(Code), ObjCStyle)); + EXPECT_EQ(Expected.str(), format(test::messUp(Code), ObjCStyle)); } } + void verifyFormat(llvm::StringRef Code, +const FormatStyle &Style = getLLVMStyle()) { +verifyFormat(Code, test::messUp(Code), Style); + } + void verifyIncompleteFormat(llvm::StringRef Code, const FormatStyle &Style = getLLVMStyle()) { EXPECT_EQ(Code.str(), @@ -11089,6 +11094,17 @@ T
r290959 - clang-format: [JS] avoid indent after ambient function declarations.
Author: mprobst Date: Wed Jan 4 07:36:43 2017 New Revision: 290959 URL: http://llvm.org/viewvc/llvm-project?rev=290959&view=rev Log: clang-format: [JS] avoid indent after ambient function declarations. Summary: Before: declare function foo(); let x = 1; After: declare function foo(); let x = 1; The problem was that clang-format would unconditionally try to parse a child block, even though ambient function declarations do not have a body (similar to forward declarations). Reviewers: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D28246 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=290959&r1=290958&r2=290959&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Wed Jan 4 07:36:43 2017 @@ -1255,10 +1255,13 @@ void UnwrappedLineParser::tryToParseJSFu if (FormatTok->is(tok::l_brace)) tryToParseBracedList(); else - while (FormatTok->isNot(tok::l_brace) && !eof()) + while (!FormatTok->isOneOf(tok::l_brace, tok::semi) && !eof()) nextToken(); } + if (FormatTok->is(tok::semi)) +return; + parseChildBlock(); } Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=290959&r1=290958&r2=290959&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Wed Jan 4 07:36:43 2017 @@ -377,6 +377,16 @@ TEST_F(FormatTestJS, AmbientDeclarations "declare function\n" "x();", // TODO(martinprobst): should ideally be indented. NineCols); + verifyFormat("declare function foo();\n" + "let x = 1;\n"); + verifyFormat("declare function foo(): string;\n" + "let x = 1;\n"); + verifyFormat("declare function foo(): {x: number};\n" + "let x = 1;\n"); + verifyFormat("declare class X {}\n" + "let x = 1;\n"); + verifyFormat("declare interface Y {}\n" + "let x = 1;\n"); verifyFormat( "declare enum X {\n" "}", ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r291428 - clang-format: [JS] ASI after imports
Author: mprobst Date: Mon Jan 9 02:56:36 2017 New Revision: 291428 URL: http://llvm.org/viewvc/llvm-project?rev=291428&view=rev Log: clang-format: [JS] ASI after imports Summary: Automatic semicolon insertion should break import and export statements: Before, this would format on one line: // Note: no semi after 'x' below! import {x} from 'x' export function foo() {} Into: import {x} from 'x' export function foo() {} With this change, the statements get separated. This also improves automatic semicolon insertion to consider closing braces preceding declarations and statements. Reviewers: klimek Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D28465 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=291428&r1=291427&r2=291428&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Mon Jan 9 02:56:36 2017 @@ -737,7 +737,7 @@ void UnwrappedLineParser::readTokenWithJ return; } if (Next->is(tok::exclaim) && PreviousMustBeValue) -addUnwrappedLine(); +return addUnwrappedLine(); bool NextMustBeValue = mustBeJSIdentOrValue(Keywords, Next); bool NextEndsTemplateExpr = Next->is(TT_TemplateString) && Next->TokenText.startswith("}"); @@ -745,9 +745,10 @@ void UnwrappedLineParser::readTokenWithJ (PreviousMustBeValue || Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus, tok::minusminus))) -addUnwrappedLine(); - if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next)) -addUnwrappedLine(); +return addUnwrappedLine(); + if ((PreviousMustBeValue || Previous->is(tok::r_brace)) && + isJSDeclOrStmt(Keywords, Next)) +return addUnwrappedLine(); } void UnwrappedLineParser::parseStructuralElement() { @@ -1974,7 +1975,14 @@ void UnwrappedLineParser::parseJavaScrip !FormatTok->isStringLiteral()) return; - while (!eof() && FormatTok->isNot(tok::semi)) { + while (!eof()) { +if (FormatTok->is(tok::semi)) + return; +if (Line->Tokens.size() == 0) { + // Common issue: Automatic Semicolon Insertion wrapped the line, so the + // import statement should terminate. + return; +} if (FormatTok->is(tok::l_brace)) { FormatTok->BlockKind = BK_Block; parseBracedList(); Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=291428&r1=291427&r2=291428&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Jan 9 02:56:36 2017 @@ -858,6 +858,24 @@ TEST_F(FormatTestJS, AutomaticSemicolonI "return 1", "a = null\n" " return 1"); + verifyFormat( + "x = {a: 1}\n" + "class Y {}", + " x = {a : 1}\n" + " class Y { }"); +} + +TEST_F(FormatTestJS, ImportExportASI) { + verifyFormat( + "import {x} from 'y'\n" + "export function z() {}", + "import {x} from 'y'\n" + " export function z() {}"); + verifyFormat( + "export {x}\n" + "class Y {}", + " export {x}\n" + " class Y {\n}"); } TEST_F(FormatTestJS, ClosureStyleCasts) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r291429 - clang-format: [JS] fix broken test.
Author: mprobst Date: Mon Jan 9 03:00:58 2017 New Revision: 291429 URL: http://llvm.org/viewvc/llvm-project?rev=291429&view=rev Log: clang-format: [JS] fix broken test. Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=291429&r1=291428&r2=291429&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Jan 9 03:00:58 2017 @@ -859,7 +859,9 @@ TEST_F(FormatTestJS, AutomaticSemicolonI "a = null\n" " return 1"); verifyFormat( - "x = {a: 1}\n" + "x = {\n" + " a: 1\n" + "}\n" "class Y {}", " x = {a : 1}\n" " class Y { }"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D23714: clang-format: [JS] handle object literals with casts.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. E.g. `{a: 1} as b`. https://reviews.llvm.org/D23714 Files: lib/Format/UnwrappedLineParser.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1218,6 +1218,7 @@ " 1, //\n" " 2\n" "];"); + verifyFormat("var x = [{x: 1} as type];"); } TEST_F(FormatTestJS, TypeArguments) { Index: lib/Format/UnwrappedLineParser.cpp === --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -364,7 +364,8 @@ // We exclude + and - as they can be ObjC visibility modifiers. ProbablyBracedList = (Style.Language == FormatStyle::LK_JavaScript && - NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in)) || + NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, +Keywords.kw_as)) || NextTok->isOneOf(tok::comma, tok::period, tok::colon, tok::r_paren, tok::r_square, tok::l_brace, tok::l_square, tok::l_paren, tok::ellipsis) || Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1218,6 +1218,7 @@ " 1, //\n" " 2\n" "];"); + verifyFormat("var x = [{x: 1} as type];"); } TEST_F(FormatTestJS, TypeArguments) { Index: lib/Format/UnwrappedLineParser.cpp === --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -364,7 +364,8 @@ // We exclude + and - as they can be ObjC visibility modifiers. ProbablyBracedList = (Style.Language == FormatStyle::LK_JavaScript && - NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in)) || + NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, +Keywords.kw_as)) || NextTok->isOneOf(tok::comma, tok::period, tok::colon, tok::r_paren, tok::r_square, tok::l_brace, tok::l_square, tok::l_paren, tok::ellipsis) || ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D22431: clang-format: [JS] nested and tagged template strings.
mprobst updated this revision to Diff 68687. mprobst added a comment. - Use a stack to parse nested template strings. - move docs - Fold GreaterStashed, LessStashed into TOKEN_STASHED lexer state. https://reviews.llvm.org/D22431 Files: lib/Format/FormatTokenLexer.cpp lib/Format/FormatTokenLexer.h lib/Format/TokenAnnotator.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1122,7 +1122,7 @@ TEST_F(FormatTestJS, TemplateStrings) { // Keeps any whitespace/indentation within the template string. verifyFormat("var x = `hello\n" -" ${ name}\n" +" ${name}\n" " !`;", "var x=`hello\n" " ${ name}\n" @@ -1208,6 +1208,16 @@ "var y;"); } +TEST_F(FormatTestJS, NestedTemplateStrings) { + verifyFormat( + "var x = `${xs.map(x => `${x}`).join('\\n')}`;"); + verifyFormat("var x = `he${({text: 'll'}.text)}o`;"); +} + +TEST_F(FormatTestJS, TaggedTemplateStrings) { + verifyFormat("var x = html``;"); +} + TEST_F(FormatTestJS, CastSyntax) { verifyFormat("var x = foo;"); verifyFormat("var x = foo as type;"); Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -858,7 +858,7 @@ if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_ForEachMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, - TT_RegexLiteral)) + TT_RegexLiteral, TT_TemplateString)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -1816,6 +1816,9 @@ return 100; if (Left.is(TT_JsTypeColon)) return 35; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return 100; } if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && @@ -2114,6 +2117,11 @@ } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return false; +if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) + return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; Index: lib/Format/FormatTokenLexer.h === --- lib/Format/FormatTokenLexer.h +++ lib/Format/FormatTokenLexer.h @@ -23,9 +23,17 @@ #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" +#include + namespace clang { namespace format { +enum LexerState { + NORMAL, + TEMPLATE_STRING, + TOKEN_STASHED, +}; + class FormatTokenLexer { public: FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, @@ -53,7 +61,16 @@ // its text if successful. void tryParseJSRegexLiteral(); - void tryParseTemplateString(); + // Handles JavaScript template strings. + // + // JavaScript template strings use backticks ('`') as delimiters, and allow + // embedding expressions nested in ${expr-here}. Template strings can be + // nested recursively, i.e. expressions can contain template strings in turns. + // + // The code below parses starting from a backtick, up to a closing backtick or + // an opening ${. It also maintains a stack of lexing contexts to handle + // nested template parts by balancing curly braces. + void handleTemplateStrings(); bool tryMerge_TMacro(); @@ -65,7 +82,7 @@ FormatToken *FormatTok; bool IsFirstToken; - bool GreaterStashed, LessStashed; + std::stack StateStack; unsigned Column; unsigned TrailingWhitespace; std::unique_ptr Lex; Index: lib/Format/FormatTokenLexer.cpp === --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -26,12 +26,11 @@ FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, const FormatStyle &Style, encoding::Encoding Encoding) -: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), - LessStashed(false), Column(0), TrailingWhitespace(0), - SourceMgr(SourceMgr), ID(ID), Style(Style), - IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), - MacroBlockBeginRegex(Style.MacroBlock
Re: [PATCH] D22431: clang-format: [JS] nested and tagged template strings.
mprobst marked 9 inline comments as done. mprobst added a comment. https://reviews.llvm.org/D22431 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r279250 - clang-format: [JS] handle object literals with casts.
Author: mprobst Date: Fri Aug 19 09:35:01 2016 New Revision: 279250 URL: http://llvm.org/viewvc/llvm-project?rev=279250&view=rev Log: clang-format: [JS] handle object literals with casts. Summary: E.g. `{a: 1} as b`. Reviewers: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D23714 Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=279250&r1=279249&r2=279250&view=diff == --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Fri Aug 19 09:35:01 2016 @@ -364,7 +364,8 @@ void UnwrappedLineParser::calculateBrace // We exclude + and - as they can be ObjC visibility modifiers. ProbablyBracedList = (Style.Language == FormatStyle::LK_JavaScript && - NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in)) || + NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, +Keywords.kw_as)) || NextTok->isOneOf(tok::comma, tok::period, tok::colon, tok::r_paren, tok::r_square, tok::l_brace, tok::l_square, tok::l_paren, tok::ellipsis) || Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=279250&r1=279249&r2=279250&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Fri Aug 19 09:35:01 2016 @@ -1218,6 +1218,7 @@ TEST_F(FormatTestJS, CastSyntax) { " 1, //\n" " 2\n" "];"); + verifyFormat("var x = [{x: 1} as type];"); } TEST_F(FormatTestJS, TypeArguments) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D23714: clang-format: [JS] handle object literals with casts.
This revision was automatically updated to reflect the committed changes. Closed by commit rL279250: clang-format: [JS] handle object literals with casts. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D23714?vs=68686&id=68688#toc Repository: rL LLVM https://reviews.llvm.org/D23714 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 @@ -364,7 +364,8 @@ // We exclude + and - as they can be ObjC visibility modifiers. ProbablyBracedList = (Style.Language == FormatStyle::LK_JavaScript && - NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in)) || + NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, +Keywords.kw_as)) || NextTok->isOneOf(tok::comma, tok::period, tok::colon, tok::r_paren, tok::r_square, tok::l_brace, tok::l_square, tok::l_paren, tok::ellipsis) || Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -1218,6 +1218,7 @@ " 1, //\n" " 2\n" "];"); + verifyFormat("var x = [{x: 1} as type];"); } TEST_F(FormatTestJS, TypeArguments) { Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp === --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp @@ -364,7 +364,8 @@ // We exclude + and - as they can be ObjC visibility modifiers. ProbablyBracedList = (Style.Language == FormatStyle::LK_JavaScript && - NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in)) || + NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, +Keywords.kw_as)) || NextTok->isOneOf(tok::comma, tok::period, tok::colon, tok::r_paren, tok::r_square, tok::l_brace, tok::l_square, tok::l_paren, tok::ellipsis) || Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -1218,6 +1218,7 @@ " 1, //\n" " 2\n" "];"); + verifyFormat("var x = [{x: 1} as type];"); } TEST_F(FormatTestJS, TypeArguments) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D23761: clang-format: [JS] supports casts to types starting with punctuation ("{[(").
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added subscribers: cfe-commits, klimek. https://reviews.llvm.org/D23761 Files: lib/Format/FormatTokenLexer.cpp lib/Format/FormatTokenLexer.h lib/Format/TokenAnnotator.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1122,7 +1122,7 @@ TEST_F(FormatTestJS, TemplateStrings) { // Keeps any whitespace/indentation within the template string. verifyFormat("var x = `hello\n" -" ${ name}\n" +" ${name}\n" " !`;", "var x=`hello\n" " ${ name}\n" @@ -1206,6 +1206,12 @@ "var y;", "var x = ` \\` a`;\n" "var y;"); + verifyFormat( + "var x = `${xs.map(x => `${x}`).join('\\n')}`;"); +} + +TEST_F(FormatTestJS, TaggedTemplateStrings) { + verifyFormat("var x = html``;"); } TEST_F(FormatTestJS, CastSyntax) { @@ -1219,6 +1225,9 @@ " 2\n" "];"); verifyFormat("var x = [{x: 1} as type];"); + verifyFormat("x = x as [a, b];"); + verifyFormat("x = x as {a: string};"); + verifyFormat("x = x as (string);"); } TEST_F(FormatTestJS, TypeArguments) { Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -858,7 +858,7 @@ if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_ForEachMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, - TT_RegexLiteral)) + TT_RegexLiteral, TT_TemplateString)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -1816,6 +1816,9 @@ return 100; if (Left.is(TT_JsTypeColon)) return 35; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return 100; } if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && @@ -2114,13 +2117,21 @@ } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return false; +if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) + return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; if (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; +if (Left.is(Keywords.kw_as) && +Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren)) + return true; if (Left.is(tok::kw_default) && Left.Previous && Left.Previous->is(tok::kw_export)) return true; Index: lib/Format/FormatTokenLexer.h === --- lib/Format/FormatTokenLexer.h +++ lib/Format/FormatTokenLexer.h @@ -66,6 +66,7 @@ FormatToken *FormatTok; bool IsFirstToken; bool GreaterStashed, LessStashed; + unsigned TemplateStringDepth; unsigned Column; unsigned TrailingWhitespace; std::unique_ptr Lex; Index: lib/Format/FormatTokenLexer.cpp === --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -27,8 +27,8 @@ const FormatStyle &Style, encoding::Encoding Encoding) : FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), - LessStashed(false), Column(0), TrailingWhitespace(0), - SourceMgr(SourceMgr), ID(ID), Style(Style), + LessStashed(false), TemplateStringDepth(0), Column(0), + TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), Style(Style), IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin), @@ -230,15 +230,25 @@ void FormatTokenLexer::tryParseTemplateString() { FormatToken *BacktickToken = Tokens.back(); - if (!BacktickToken->is(tok::unknown) || BacktickToken->TokenText != "`") + if (TemplateStringDepth > 0 && BacktickToken->TokenText == "}") +TemplateStringDepth--; + else if (!BacktickToken->is(tok::unknown) || + BacktickToken->TokenText != "`") return; //
Re: [PATCH] D23761: clang-format: [JS] supports casts to types starting with punctuation ("{[(").
mprobst updated this revision to Diff 68844. mprobst added a comment. - drop accidentally included template string patch from this diff. https://reviews.llvm.org/D23761 Files: lib/Format/TokenAnnotator.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1219,6 +1219,9 @@ " 2\n" "];"); verifyFormat("var x = [{x: 1} as type];"); + verifyFormat("x = x as [a, b];"); + verifyFormat("x = x as {a: string};"); + verifyFormat("x = x as (string);"); } TEST_F(FormatTestJS, TypeArguments) { Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -2121,6 +2121,9 @@ Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; +if (Left.is(Keywords.kw_as) && +Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren)) + return true; if (Left.is(tok::kw_default) && Left.Previous && Left.Previous->is(tok::kw_export)) return true; Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1219,6 +1219,9 @@ " 2\n" "];"); verifyFormat("var x = [{x: 1} as type];"); + verifyFormat("x = x as [a, b];"); + verifyFormat("x = x as {a: string};"); + verifyFormat("x = x as (string);"); } TEST_F(FormatTestJS, TypeArguments) { Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -2121,6 +2121,9 @@ Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; +if (Left.is(Keywords.kw_as) && +Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren)) + return true; if (Left.is(tok::kw_default) && Left.Previous && Left.Previous->is(tok::kw_export)) return true; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D23761: clang-format: [JS] supports casts to types starting with punctuation ("{[(").
mprobst marked an inline comment as done. Comment at: lib/Format/FormatTokenLexer.cpp:245 @@ -241,1 +244,3 @@ ++Offset; // Skip the escaped character. +if (Offset + 1 < Lex->getBuffer().end() && *Offset == '$' && +*(Offset + 1) == '{') { ygao wrote: > What happens if the '${' is immediately after a backslash (the if statement > above), should the '${' get escaped? Sorry, I accidentally included this in the wrong diff – the template string thing is in D22431. I'll answer there. https://reviews.llvm.org/D23761 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D22431: clang-format: [JS] nested and tagged template strings.
mprobst updated this revision to Diff 68851. mprobst added a comment. - Test escaped dollar sign. https://reviews.llvm.org/D22431 Files: lib/Format/FormatTokenLexer.cpp lib/Format/FormatTokenLexer.h lib/Format/TokenAnnotator.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1122,7 +1122,7 @@ TEST_F(FormatTestJS, TemplateStrings) { // Keeps any whitespace/indentation within the template string. verifyFormat("var x = `hello\n" -" ${ name}\n" +" ${name}\n" " !`;", "var x=`hello\n" " ${ name}\n" @@ -1206,6 +1206,18 @@ "var y;", "var x = ` \\` a`;\n" "var y;"); + // Escaped dollar. + verifyFormat("var x = ` \\${foo}`;\n"); +} + +TEST_F(FormatTestJS, NestedTemplateStrings) { + verifyFormat( + "var x = `${xs.map(x => `${x}`).join('\\n')}`;"); + verifyFormat("var x = `he${({text: 'll'}.text)}o`;"); +} + +TEST_F(FormatTestJS, TaggedTemplateStrings) { + verifyFormat("var x = html``;"); } TEST_F(FormatTestJS, CastSyntax) { Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -858,7 +858,7 @@ if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_ForEachMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, - TT_RegexLiteral)) + TT_RegexLiteral, TT_TemplateString)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -1816,6 +1816,9 @@ return 100; if (Left.is(TT_JsTypeColon)) return 35; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return 100; } if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && @@ -2114,6 +2117,11 @@ } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return false; +if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) + return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; Index: lib/Format/FormatTokenLexer.h === --- lib/Format/FormatTokenLexer.h +++ lib/Format/FormatTokenLexer.h @@ -23,9 +23,17 @@ #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" +#include + namespace clang { namespace format { +enum LexerState { + NORMAL, + TEMPLATE_STRING, + TOKEN_STASHED, +}; + class FormatTokenLexer { public: FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, @@ -53,7 +61,16 @@ // its text if successful. void tryParseJSRegexLiteral(); - void tryParseTemplateString(); + // Handles JavaScript template strings. + // + // JavaScript template strings use backticks ('`') as delimiters, and allow + // embedding expressions nested in ${expr-here}. Template strings can be + // nested recursively, i.e. expressions can contain template strings in turns. + // + // The code below parses starting from a backtick, up to a closing backtick or + // an opening ${. It also maintains a stack of lexing contexts to handle + // nested template parts by balancing curly braces. + void handleTemplateStrings(); bool tryMerge_TMacro(); @@ -65,7 +82,7 @@ FormatToken *FormatTok; bool IsFirstToken; - bool GreaterStashed, LessStashed; + std::stack StateStack; unsigned Column; unsigned TrailingWhitespace; std::unique_ptr Lex; Index: lib/Format/FormatTokenLexer.cpp === --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -26,12 +26,11 @@ FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, const FormatStyle &Style, encoding::Encoding Encoding) -: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), - LessStashed(false), Column(0), TrailingWhitespace(0), - SourceMgr(SourceMgr), ID(ID), Style(Style), - IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), - MacroBlockBeginRegex(Style.MacroBlockBegin), +: FormatTok(nullptr), IsFirstTo
Re: [PATCH] D22431: clang-format: [JS] nested and tagged template strings.
mprobst added inline comments. Comment at: lib/Format/FormatTokenLexer.cpp:259 @@ -241,1 +258,3 @@ ++Offset; // Skip the escaped character. +if (Offset + 1 < Lex->getBuffer().end() && Offset[0] == '$' && +Offset[1] == '{') { Question by @ygao in the other diff: > What happens if the '${' is immediately after a backslash (the if statement > above), should the '${' get escaped? A template like `foo\${bar}` is the literal string `'foo\${bar}'`, i.e. the `\` acts as an escape for the `'$'` sign. I've added a test to validate that. https://reviews.llvm.org/D22431 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D22431: clang-format: [JS] nested and tagged template strings.
mprobst updated this revision to Diff 68853. mprobst added a comment. - Fix escaping issue. https://reviews.llvm.org/D22431 Files: lib/Format/FormatTokenLexer.cpp lib/Format/FormatTokenLexer.h lib/Format/TokenAnnotator.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1122,7 +1122,7 @@ TEST_F(FormatTestJS, TemplateStrings) { // Keeps any whitespace/indentation within the template string. verifyFormat("var x = `hello\n" -" ${ name}\n" +" ${name}\n" " !`;", "var x=`hello\n" " ${ name}\n" @@ -1206,6 +1206,18 @@ "var y;", "var x = ` \\` a`;\n" "var y;"); + // Escaped dollar. + verifyFormat("var x = ` \\${foo}`;\n"); +} + +TEST_F(FormatTestJS, NestedTemplateStrings) { + verifyFormat( + "var x = `${xs.map(x => `${x}`).join('\\n')}`;"); + verifyFormat("var x = `he${({text: 'll'}.text)}o`;"); +} + +TEST_F(FormatTestJS, TaggedTemplateStrings) { + verifyFormat("var x = html``;"); } TEST_F(FormatTestJS, CastSyntax) { Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -858,7 +858,7 @@ if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_ForEachMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, - TT_RegexLiteral)) + TT_RegexLiteral, TT_TemplateString)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -1816,6 +1816,9 @@ return 100; if (Left.is(TT_JsTypeColon)) return 35; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return 100; } if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && @@ -2114,6 +2117,11 @@ } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; +if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || +(Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) + return false; +if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) + return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; Index: lib/Format/FormatTokenLexer.h === --- lib/Format/FormatTokenLexer.h +++ lib/Format/FormatTokenLexer.h @@ -23,9 +23,17 @@ #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" +#include + namespace clang { namespace format { +enum LexerState { + NORMAL, + TEMPLATE_STRING, + TOKEN_STASHED, +}; + class FormatTokenLexer { public: FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, @@ -53,7 +61,16 @@ // its text if successful. void tryParseJSRegexLiteral(); - void tryParseTemplateString(); + // Handles JavaScript template strings. + // + // JavaScript template strings use backticks ('`') as delimiters, and allow + // embedding expressions nested in ${expr-here}. Template strings can be + // nested recursively, i.e. expressions can contain template strings in turns. + // + // The code below parses starting from a backtick, up to a closing backtick or + // an opening ${. It also maintains a stack of lexing contexts to handle + // nested template parts by balancing curly braces. + void handleTemplateStrings(); bool tryMerge_TMacro(); @@ -65,7 +82,7 @@ FormatToken *FormatTok; bool IsFirstToken; - bool GreaterStashed, LessStashed; + std::stack StateStack; unsigned Column; unsigned TrailingWhitespace; std::unique_ptr Lex; Index: lib/Format/FormatTokenLexer.cpp === --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -26,12 +26,11 @@ FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, const FormatStyle &Style, encoding::Encoding Encoding) -: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), - LessStashed(false), Column(0), TrailingWhitespace(0), - SourceMgr(SourceMgr), ID(ID), Style(Style), - IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), - MacroBlockBeginRegex(Style.MacroBlockBegin), +: FormatTok(nullptr), IsFirstToken(tr
r279436 - clang-format: [JS] supports casts to types starting with punctuation ("{[(").
Author: mprobst Date: Mon Aug 22 09:23:30 2016 New Revision: 279436 URL: http://llvm.org/viewvc/llvm-project?rev=279436&view=rev Log: clang-format: [JS] supports casts to types starting with punctuation ("{[("). Before: x as{x: number} After: x as {x: number} Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D23761 Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=279436&r1=279435&r2=279436&view=diff == --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Aug 22 09:23:30 2016 @@ -2121,6 +2121,9 @@ bool TokenAnnotator::spaceRequiredBefore Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; +if (Left.is(Keywords.kw_as) && +Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren)) + return true; if (Left.is(tok::kw_default) && Left.Previous && Left.Previous->is(tok::kw_export)) return true; Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=279436&r1=279435&r2=279436&view=diff == --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Mon Aug 22 09:23:30 2016 @@ -1219,6 +1219,9 @@ TEST_F(FormatTestJS, CastSyntax) { " 2\n" "];"); verifyFormat("var x = [{x: 1} as type];"); + verifyFormat("x = x as [a, b];"); + verifyFormat("x = x as {a: string};"); + verifyFormat("x = x as (string);"); } TEST_F(FormatTestJS, TypeArguments) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D23761: clang-format: [JS] supports casts to types starting with punctuation ("{[(").
This revision was automatically updated to reflect the committed changes. mprobst marked an inline comment as done. Closed by commit rL279436: clang-format: [JS] supports casts to types starting with punctuation ("{[("). (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D23761?vs=68844&id=68858#toc Repository: rL LLVM https://reviews.llvm.org/D23761 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 @@ -2121,6 +2121,9 @@ Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; +if (Left.is(Keywords.kw_as) && +Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren)) + return true; if (Left.is(tok::kw_default) && Left.Previous && Left.Previous->is(tok::kw_export)) return true; Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -1219,6 +1219,9 @@ " 2\n" "];"); verifyFormat("var x = [{x: 1} as type];"); + verifyFormat("x = x as [a, b];"); + verifyFormat("x = x as {a: string};"); + verifyFormat("x = x as (string);"); } TEST_F(FormatTestJS, TypeArguments) { Index: cfe/trunk/lib/Format/TokenAnnotator.cpp === --- cfe/trunk/lib/Format/TokenAnnotator.cpp +++ cfe/trunk/lib/Format/TokenAnnotator.cpp @@ -2121,6 +2121,9 @@ Keywords.kw_of, tok::kw_const) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; +if (Left.is(Keywords.kw_as) && +Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren)) + return true; if (Left.is(tok::kw_default) && Left.Previous && Left.Previous->is(tok::kw_export)) return true; Index: cfe/trunk/unittests/Format/FormatTestJS.cpp === --- cfe/trunk/unittests/Format/FormatTestJS.cpp +++ cfe/trunk/unittests/Format/FormatTestJS.cpp @@ -1219,6 +1219,9 @@ " 2\n" "];"); verifyFormat("var x = [{x: 1} as type];"); + verifyFormat("x = x as [a, b];"); + verifyFormat("x = x as {a: string};"); + verifyFormat("x = x as (string);"); } TEST_F(FormatTestJS, TypeArguments) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D22431: clang-format: [JS] nested and tagged template strings.
mprobst added a comment. No worries, thanks for the review. https://reviews.llvm.org/D22431 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r279727 - clang-format: [JS] nested and tagged template strings.
Author: mprobst Date: Thu Aug 25 05:13:21 2016 New Revision: 279727 URL: http://llvm.org/viewvc/llvm-project?rev=279727&view=rev Log: clang-format: [JS] nested and tagged template strings. JavaScript template strings can be nested arbitrarily: foo = `text ${es.map(e => { return `<${e}>`; })} text`; This change lexes nested template strings using a stack of lexer states to correctly switch back to template string lexing on closing braces. Also, reuse the same stack for the token-stashed logic. Reviewers: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D22431 Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp cfe/trunk/lib/Format/FormatTokenLexer.h cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.cpp?rev=279727&r1=279726&r2=279727&view=diff == --- cfe/trunk/lib/Format/FormatTokenLexer.cpp (original) +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp Thu Aug 25 05:13:21 2016 @@ -26,12 +26,11 @@ namespace format { FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, const FormatStyle &Style, encoding::Encoding Encoding) -: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), - LessStashed(false), Column(0), TrailingWhitespace(0), - SourceMgr(SourceMgr), ID(ID), Style(Style), - IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), - MacroBlockBeginRegex(Style.MacroBlockBegin), +: FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}), + Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), + Style(Style), IdentTable(getFormattingLangOpts(Style)), + Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0), + FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin), MacroBlockEndRegex(Style.MacroBlockEnd) { Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts(Style))); @@ -49,7 +48,7 @@ ArrayRef FormatTokenLexer Tokens.push_back(getNextToken()); if (Style.Language == FormatStyle::LK_JavaScript) { tryParseJSRegexLiteral(); - tryParseTemplateString(); + handleTemplateStrings(); } tryMergePreviousTokens(); if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline) @@ -228,17 +227,42 @@ void FormatTokenLexer::tryParseJSRegexLi resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset))); } -void FormatTokenLexer::tryParseTemplateString() { +void FormatTokenLexer::handleTemplateStrings() { FormatToken *BacktickToken = Tokens.back(); - if (!BacktickToken->is(tok::unknown) || BacktickToken->TokenText != "`") + + if (BacktickToken->is(tok::l_brace)) { +StateStack.push(LexerState::NORMAL); return; + } + if (BacktickToken->is(tok::r_brace)) { +StateStack.pop(); +if (StateStack.top() != LexerState::TEMPLATE_STRING) + return; +// If back in TEMPLATE_STRING, fallthrough and continue parsing the + } else if (BacktickToken->is(tok::unknown) && + BacktickToken->TokenText == "`") { +StateStack.push(LexerState::TEMPLATE_STRING); + } else { +return; // Not actually a template + } // 'Manually' lex ahead in the current file buffer. const char *Offset = Lex->getBufferLocation(); const char *TmplBegin = Offset - BacktickToken->TokenText.size(); // at "`" - for (; Offset != Lex->getBuffer().end() && *Offset != '`'; ++Offset) { -if (*Offset == '\\') + for (; Offset != Lex->getBuffer().end(); ++Offset) { +if (Offset[0] == '`') { + StateStack.pop(); + break; +} +if (Offset[0] == '\\') { ++Offset; // Skip the escaped character. +} else if (Offset + 1 < Lex->getBuffer().end() && Offset[0] == '$' && + Offset[1] == '{') { + // '${' introduces an expression interpolation in the template string. + StateStack.push(LexerState::NORMAL); + ++Offset; + break; +} } StringRef LiteralText(TmplBegin, Offset - TmplBegin + 1); @@ -262,7 +286,10 @@ void FormatTokenLexer::tryParseTemplateS Style.TabWidth, Encoding); } - resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset + 1))); + SourceLocation loc = Offset < Lex->getBuffer().end() + ? Lex->getSourceLocation(Offset + 1) + : SourceMgr.getLocForEndOfFile(ID); + resetLexer(SourceMgr.getFileOffset(loc)); } bool FormatTokenLexer::tryMerge_TMacro() { @@ -384,12 +411,8 @@ FormatToken *FormatTokenLexer::getStashe } FormatToken *FormatTokenLexer::getNextToken() { -
Re: [PATCH] D22431: clang-format: [JS] nested and tagged template strings.
This revision was automatically updated to reflect the committed changes. Closed by commit rL279727: clang-format: [JS] nested and tagged template strings. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D22431?vs=68853&id=69219#toc Repository: rL LLVM https://reviews.llvm.org/D22431 Files: cfe/trunk/lib/Format/FormatTokenLexer.cpp cfe/trunk/lib/Format/FormatTokenLexer.h cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTestJS.cpp Index: cfe/trunk/lib/Format/FormatTokenLexer.h === --- cfe/trunk/lib/Format/FormatTokenLexer.h +++ cfe/trunk/lib/Format/FormatTokenLexer.h @@ -23,9 +23,17 @@ #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" +#include + namespace clang { namespace format { +enum LexerState { + NORMAL, + TEMPLATE_STRING, + TOKEN_STASHED, +}; + class FormatTokenLexer { public: FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, @@ -53,7 +61,16 @@ // its text if successful. void tryParseJSRegexLiteral(); - void tryParseTemplateString(); + // Handles JavaScript template strings. + // + // JavaScript template strings use backticks ('`') as delimiters, and allow + // embedding expressions nested in ${expr-here}. Template strings can be + // nested recursively, i.e. expressions can contain template strings in turn. + // + // The code below parses starting from a backtick, up to a closing backtick or + // an opening ${. It also maintains a stack of lexing contexts to handle + // nested template parts by balancing curly braces. + void handleTemplateStrings(); bool tryMerge_TMacro(); @@ -65,7 +82,7 @@ FormatToken *FormatTok; bool IsFirstToken; - bool GreaterStashed, LessStashed; + std::stack StateStack; unsigned Column; unsigned TrailingWhitespace; std::unique_ptr Lex; Index: cfe/trunk/lib/Format/FormatTokenLexer.cpp === --- cfe/trunk/lib/Format/FormatTokenLexer.cpp +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp @@ -26,12 +26,11 @@ FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, const FormatStyle &Style, encoding::Encoding Encoding) -: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), - LessStashed(false), Column(0), TrailingWhitespace(0), - SourceMgr(SourceMgr), ID(ID), Style(Style), - IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), - MacroBlockBeginRegex(Style.MacroBlockBegin), +: FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}), + Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), + Style(Style), IdentTable(getFormattingLangOpts(Style)), + Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0), + FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin), MacroBlockEndRegex(Style.MacroBlockEnd) { Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts(Style))); @@ -49,7 +48,7 @@ Tokens.push_back(getNextToken()); if (Style.Language == FormatStyle::LK_JavaScript) { tryParseJSRegexLiteral(); - tryParseTemplateString(); + handleTemplateStrings(); } tryMergePreviousTokens(); if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline) @@ -228,17 +227,42 @@ resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset))); } -void FormatTokenLexer::tryParseTemplateString() { +void FormatTokenLexer::handleTemplateStrings() { FormatToken *BacktickToken = Tokens.back(); - if (!BacktickToken->is(tok::unknown) || BacktickToken->TokenText != "`") + + if (BacktickToken->is(tok::l_brace)) { +StateStack.push(LexerState::NORMAL); return; + } + if (BacktickToken->is(tok::r_brace)) { +StateStack.pop(); +if (StateStack.top() != LexerState::TEMPLATE_STRING) + return; +// If back in TEMPLATE_STRING, fallthrough and continue parsing the + } else if (BacktickToken->is(tok::unknown) && + BacktickToken->TokenText == "`") { +StateStack.push(LexerState::TEMPLATE_STRING); + } else { +return; // Not actually a template + } // 'Manually' lex ahead in the current file buffer. const char *Offset = Lex->getBufferLocation(); const char *TmplBegin = Offset - BacktickToken->TokenText.size(); // at "`" - for (; Offset != Lex->getBuffer().end() && *Offset != '`'; ++Offset) { -if (*Offset == '\\') + for (; Offset != Lex->getBuffer().end(); ++Offset) { +if (Offset[0] == '`') { + StateStack.pop(); + break; +} +if (Offset[0] == '\\') { ++Offset; // Skip the escaped character. +} else if (Offset + 1 < Lex->getBuffer().end() && Offset[0] == '$' && +
[PATCH] D23972: clang-format: [JS] Sort all JavaScript imports if any changed.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. User feedback is that they expect *all* imports to be sorted if any import was affected by a change, not just imports up to the first non-affected line, as clang-format currently does. https://reviews.llvm.org/D23972 Files: lib/Format/SortJavaScriptImports.cpp unittests/Format/SortImportsTestJS.cpp Index: unittests/Format/SortImportsTestJS.cpp === --- unittests/Format/SortImportsTestJS.cpp +++ unittests/Format/SortImportsTestJS.cpp @@ -190,40 +190,29 @@ } TEST_F(SortImportsTestJS, AffectedRange) { - // Sort excluding a suffix. - verifySort("import {sym} from 'b';\n" + // Affected range inside of import statements. + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" "import {sym} from 'c';\n" - "import {sym} from 'a';\n" + "\n" "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "let x = 1;", 0, 30); - // Sort excluding a prefix. + // Affected range outside of import statements. verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "\n" - "let x = 1;", - "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "\n" "let x = 1;", - 30, 0); - // Sort a range within imports. - verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "import {sym} from 'c';\n" - "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" - "import {sym} from 'c';\n" + "\n" "let x = 1;", - 24, 30); + 70, 1); } TEST_F(SortImportsTestJS, SortingCanShrink) { Index: lib/Format/SortJavaScriptImports.cpp === --- lib/Format/SortJavaScriptImports.cpp +++ lib/Format/SortJavaScriptImports.cpp @@ -284,14 +284,8 @@ SourceLocation Start; bool FoundLines = false; AnnotatedLine *FirstNonImportLine = nullptr; +bool AnyImportAffected = false; for (auto Line : AnnotatedLines) { - if (!Line->Affected) { -// Only sort the first contiguous block of affected lines. -if (FoundLines) - break; -else - continue; - } Current = Line->First; LineEnd = Line->Last; skipComments(); @@ -309,6 +303,7 @@ FirstNonImportLine = Line; break; } + AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ llvm::dbgs() << "JsModuleReference: {" @@ -325,6 +320,9 @@ References.push_back(Reference); Start = SourceLocation(); } +// Sort imports if any import line was affected. +if (!AnyImportAffected) + References.clear(); return std::make_pair(References, FirstNonImportLine); } Index: unittests/Format/SortImportsTestJS.cpp === --- unittests/Format/SortImportsTestJS.cpp +++ unittests/Format/SortImportsTestJS.cpp @@ -190,40 +190,29 @@ } TEST_F(SortImportsTestJS, AffectedRange) { - // Sort excluding a suffix. - verifySort("import {sym} from 'b';\n" + // Affected range inside of import statements. + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" "import {sym} from 'c';\n" - "import {sym} from 'a';\n" + "\n" "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "let x = 1;", 0, 30); - // Sort excluding a prefix. + // Affected range outside of import statements. verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "\n" - "let x = 1;", - "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "\n" "let x = 1;", - 30, 0); - // Sort a range within imports. - verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "import {sym} from 'c';\n" - "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" -
[PATCH] D23973: clang-format: [JS] handle default bindings in imports.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. Default imports appear outside of named bindings in curly braces: import A from 'a'; import A, {symbol} from 'a'; https://reviews.llvm.org/D23973 Files: lib/Format/SortJavaScriptImports.cpp unittests/Format/SortImportsTestJS.cpp Index: unittests/Format/SortImportsTestJS.cpp === --- unittests/Format/SortImportsTestJS.cpp +++ unittests/Format/SortImportsTestJS.cpp @@ -70,6 +70,26 @@ "let x = 1;"); } +TEST_F(SortImportsTestJS, DefaultBinding) { + verifySort("import A from 'a';\n" + "import B from 'b';\n" + "\n" + "let x = 1;", + "import B from 'b';\n" + "import A from 'a';\n" + "let x = 1;"); +} + +TEST_F(SortImportsTestJS, DefaultAndNamedBinding) { + verifySort("import A, {a} from 'a';\n" + "import B, {b} from 'b';\n" + "\n" + "let x = 1;", + "import B, {b} from 'b';\n" + "import A, {a} from 'a';\n" + "let x = 1;"); +} + TEST_F(SortImportsTestJS, WrappedImportStatements) { verifySort("import {sym1, sym2} from 'a';\n" "import {sym} from 'b';\n" Index: lib/Format/SortJavaScriptImports.cpp === --- lib/Format/SortJavaScriptImports.cpp +++ lib/Format/SortJavaScriptImports.cpp @@ -348,7 +348,6 @@ if (!parseModuleBindings(Keywords, Reference)) return false; -nextToken(); if (Current->is(Keywords.kw_from)) { // imports have a 'from' clause, exports might not. @@ -391,19 +390,28 @@ if (Current->isNot(tok::identifier)) return false; Reference.Prefix = Current->TokenText; +nextToken(); return true; } bool parseNamedBindings(const AdditionalKeywords &Keywords, JsModuleReference &Reference) { +if (Current->is(tok::identifier)) { + nextToken(); + if (Current->is(Keywords.kw_from)) +return true; + if (Current->isNot(tok::comma)) +return false; + nextToken(); // eat comma. +} if (Current->isNot(tok::l_brace)) return false; // {sym as alias, sym2 as ...} from '...'; -nextToken(); -while (true) { +while (Current->isNot(tok::r_brace)) { + nextToken(); if (Current->is(tok::r_brace)) -return true; +break; if (Current->isNot(tok::identifier)) return false; @@ -424,12 +432,11 @@ Symbol.Range.setEnd(Current->Tok.getLocation()); Reference.Symbols.push_back(Symbol); - if (Current->is(tok::r_brace)) -return true; - if (Current->isNot(tok::comma)) + if (!Current->isOneOf(tok::r_brace, tok::comma)) return false; - nextToken(); } +nextToken(); // consume r_brace +return true; } }; Index: unittests/Format/SortImportsTestJS.cpp === --- unittests/Format/SortImportsTestJS.cpp +++ unittests/Format/SortImportsTestJS.cpp @@ -70,6 +70,26 @@ "let x = 1;"); } +TEST_F(SortImportsTestJS, DefaultBinding) { + verifySort("import A from 'a';\n" + "import B from 'b';\n" + "\n" + "let x = 1;", + "import B from 'b';\n" + "import A from 'a';\n" + "let x = 1;"); +} + +TEST_F(SortImportsTestJS, DefaultAndNamedBinding) { + verifySort("import A, {a} from 'a';\n" + "import B, {b} from 'b';\n" + "\n" + "let x = 1;", + "import B, {b} from 'b';\n" + "import A, {a} from 'a';\n" + "let x = 1;"); +} + TEST_F(SortImportsTestJS, WrappedImportStatements) { verifySort("import {sym1, sym2} from 'a';\n" "import {sym} from 'b';\n" Index: lib/Format/SortJavaScriptImports.cpp === --- lib/Format/SortJavaScriptImports.cpp +++ lib/Format/SortJavaScriptImports.cpp @@ -348,7 +348,6 @@ if (!parseModuleBindings(Keywords, Reference)) return false; -nextToken(); if (Current->is(Keywords.kw_from)) { // imports have a 'from' clause, exports might not. @@ -391,19 +390,28 @@ if (Current->isNot(tok::identifier)) return false; Reference.Prefix = Current->TokenText; +nextToken(); return true; } bool parseNamedBindings(const AdditionalKeywords &Keywords, JsModuleReference &Reference) { +if (Current->is(tok::identifier)) { + nextToken(); + if (Current->is(Keywords.kw_from)) +return true; + if (Current->isNot(tok::comma)) +return false; + nextToken(); // eat comma. +} if (Current->isNot(tok::l_brace)) return
[PATCH] D24155: clang-format: [JS] merge requoting replacements.
mprobst created this revision. mprobst added a reviewer: djasper. mprobst added a subscriber: cfe-commits. Herald added a subscriber: klimek. When formatting source code that needs both requoting and reindentation, merge the replacements to avoid erroring out for conflicting replacements. https://reviews.llvm.org/D24155 Files: lib/Format/Format.cpp unittests/Format/FormatTestJS.cpp Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1318,6 +1318,13 @@ "let x = \"single\";\n"); } +TEST_F(FormatTestJS, RequoteAndIndent) { + verifyFormat("let x = someVeryLongFunctionThatGoesOnAndOn(\n" + "'double quoted string that needs wrapping');", + "let x = someVeryLongFunctionThatGoesOnAndOn(" + "\"double quoted string that needs wrapping\");"); +} + TEST_F(FormatTestJS, RequoteStringsDouble) { FormatStyle DoubleQuotes = getGoogleStyle(FormatStyle::LK_JavaScript); DoubleQuotes.JavaScriptQuotes = FormatStyle::JSQS_Double; Index: lib/Format/Format.cpp === --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -803,13 +803,14 @@ analyze(TokenAnnotator &Annotator, SmallVectorImpl &AnnotatedLines, FormatTokenLexer &Tokens, tooling::Replacements &Result) override { +tooling::Replacements RunResult; deriveLocalStyle(AnnotatedLines); AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end()); if (Style.Language == FormatStyle::LK_JavaScript && Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) - requoteJSStringLiteral(AnnotatedLines, Result); + requoteJSStringLiteral(AnnotatedLines, RunResult); for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { Annotator.calculateFormattingInformation(*AnnotatedLines[i]); @@ -826,7 +827,8 @@ UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(), IncompleteFormat) .format(AnnotatedLines); -return Whitespaces.generateReplacements(); +RunResult = RunResult.merge(Whitespaces.generateReplacements()); +return RunResult; } private: Index: unittests/Format/FormatTestJS.cpp === --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1318,6 +1318,13 @@ "let x = \"single\";\n"); } +TEST_F(FormatTestJS, RequoteAndIndent) { + verifyFormat("let x = someVeryLongFunctionThatGoesOnAndOn(\n" + "'double quoted string that needs wrapping');", + "let x = someVeryLongFunctionThatGoesOnAndOn(" + "\"double quoted string that needs wrapping\");"); +} + TEST_F(FormatTestJS, RequoteStringsDouble) { FormatStyle DoubleQuotes = getGoogleStyle(FormatStyle::LK_JavaScript); DoubleQuotes.JavaScriptQuotes = FormatStyle::JSQS_Double; Index: lib/Format/Format.cpp === --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -803,13 +803,14 @@ analyze(TokenAnnotator &Annotator, SmallVectorImpl &AnnotatedLines, FormatTokenLexer &Tokens, tooling::Replacements &Result) override { +tooling::Replacements RunResult; deriveLocalStyle(AnnotatedLines); AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end()); if (Style.Language == FormatStyle::LK_JavaScript && Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) - requoteJSStringLiteral(AnnotatedLines, Result); + requoteJSStringLiteral(AnnotatedLines, RunResult); for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { Annotator.calculateFormattingInformation(*AnnotatedLines[i]); @@ -826,7 +827,8 @@ UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(), IncompleteFormat) .format(AnnotatedLines); -return Whitespaces.generateReplacements(); +RunResult = RunResult.merge(Whitespaces.generateReplacements()); +return RunResult; } private: ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D23973: clang-format: [JS] handle default bindings in imports.
mprobst added a comment. Friendly ping. https://reviews.llvm.org/D23973 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D23972: clang-format: [JS] Sort all JavaScript imports if any changed.
mprobst added a comment. Friendly ping. https://reviews.llvm.org/D23972 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r280485 - clang-format: [JS] Sort all JavaScript imports if any changed.
Author: mprobst Date: Fri Sep 2 09:01:17 2016 New Revision: 280485 URL: http://llvm.org/viewvc/llvm-project?rev=280485&view=rev Log: clang-format: [JS] Sort all JavaScript imports if any changed. Summary: User feedback is that they expect *all* imports to be sorted if any import was affected by a change, not just imports up to the first non-affected line, as clang-format currently does. Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D23972 Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp cfe/trunk/unittests/Format/SortImportsTestJS.cpp Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/SortJavaScriptImports.cpp?rev=280485&r1=280484&r2=280485&view=diff == --- cfe/trunk/lib/Format/SortJavaScriptImports.cpp (original) +++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp Fri Sep 2 09:01:17 2016 @@ -284,14 +284,8 @@ private: SourceLocation Start; bool FoundLines = false; AnnotatedLine *FirstNonImportLine = nullptr; +bool AnyImportAffected = false; for (auto Line : AnnotatedLines) { - if (!Line->Affected) { -// Only sort the first contiguous block of affected lines. -if (FoundLines) - break; -else - continue; - } Current = Line->First; LineEnd = Line->Last; skipComments(); @@ -309,6 +303,7 @@ private: FirstNonImportLine = Line; break; } + AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ llvm::dbgs() << "JsModuleReference: {" @@ -325,6 +320,9 @@ private: References.push_back(Reference); Start = SourceLocation(); } +// Sort imports if any import line was affected. +if (!AnyImportAffected) + References.clear(); return std::make_pair(References, FirstNonImportLine); } Modified: cfe/trunk/unittests/Format/SortImportsTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/SortImportsTestJS.cpp?rev=280485&r1=280484&r2=280485&view=diff == --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp (original) +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp Fri Sep 2 09:01:17 2016 @@ -190,40 +190,29 @@ TEST_F(SortImportsTestJS, SideEffectImpo } TEST_F(SortImportsTestJS, AffectedRange) { - // Sort excluding a suffix. - verifySort("import {sym} from 'b';\n" + // Affected range inside of import statements. + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" "import {sym} from 'c';\n" - "import {sym} from 'a';\n" + "\n" "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "let x = 1;", 0, 30); - // Sort excluding a prefix. + // Affected range outside of import statements. verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "\n" - "let x = 1;", - "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "\n" "let x = 1;", - 30, 0); - // Sort a range within imports. - verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "import {sym} from 'c';\n" - "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" - "import {sym} from 'c';\n" + "\n" "let x = 1;", - 24, 30); + 70, 1); } TEST_F(SortImportsTestJS, SortingCanShrink) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D23972: clang-format: [JS] Sort all JavaScript imports if any changed.
This revision was automatically updated to reflect the committed changes. Closed by commit rL280485: clang-format: [JS] Sort all JavaScript imports if any changed. (authored by mprobst). Changed prior to commit: https://reviews.llvm.org/D23972?vs=69511&id=70158#toc Repository: rL LLVM https://reviews.llvm.org/D23972 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 @@ -284,14 +284,8 @@ SourceLocation Start; bool FoundLines = false; AnnotatedLine *FirstNonImportLine = nullptr; +bool AnyImportAffected = false; for (auto Line : AnnotatedLines) { - if (!Line->Affected) { -// Only sort the first contiguous block of affected lines. -if (FoundLines) - break; -else - continue; - } Current = Line->First; LineEnd = Line->Last; skipComments(); @@ -309,6 +303,7 @@ FirstNonImportLine = Line; break; } + AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ llvm::dbgs() << "JsModuleReference: {" @@ -325,6 +320,9 @@ References.push_back(Reference); Start = SourceLocation(); } +// Sort imports if any import line was affected. +if (!AnyImportAffected) + References.clear(); return std::make_pair(References, FirstNonImportLine); } Index: cfe/trunk/unittests/Format/SortImportsTestJS.cpp === --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp @@ -190,40 +190,29 @@ } TEST_F(SortImportsTestJS, AffectedRange) { - // Sort excluding a suffix. - verifySort("import {sym} from 'b';\n" + // Affected range inside of import statements. + verifySort("import {sym} from 'a';\n" + "import {sym} from 'b';\n" "import {sym} from 'c';\n" - "import {sym} from 'a';\n" + "\n" "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "let x = 1;", 0, 30); - // Sort excluding a prefix. + // Affected range outside of import statements. verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "\n" - "let x = 1;", - "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" "\n" "let x = 1;", - 30, 0); - // Sort a range within imports. - verifySort("import {sym} from 'c';\n" - "import {sym} from 'a';\n" - "import {sym} from 'b';\n" - "import {sym} from 'c';\n" - "let x = 1;", "import {sym} from 'c';\n" "import {sym} from 'b';\n" "import {sym} from 'a';\n" - "import {sym} from 'c';\n" + "\n" "let x = 1;", - 24, 30); + 70, 1); } TEST_F(SortImportsTestJS, SortingCanShrink) { Index: cfe/trunk/lib/Format/SortJavaScriptImports.cpp === --- cfe/trunk/lib/Format/SortJavaScriptImports.cpp +++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp @@ -284,14 +284,8 @@ SourceLocation Start; bool FoundLines = false; AnnotatedLine *FirstNonImportLine = nullptr; +bool AnyImportAffected = false; for (auto Line : AnnotatedLines) { - if (!Line->Affected) { -// Only sort the first contiguous block of affected lines. -if (FoundLines) - break; -else - continue; - } Current = Line->First; LineEnd = Line->Last; skipComments(); @@ -309,6 +303,7 @@ FirstNonImportLine = Line; break; } + AnyImportAffected = AnyImportAffected || Line->Affected; Reference.Range.setEnd(LineEnd->Tok.getEndLoc()); DEBUG({ llvm::dbgs() << "JsModuleReference: {" @@ -325,6 +320,9 @@ References.push_back(Reference); Start = SourceLocation(); } +// Sort imports if any import line was affected. +if (!AnyImportAffected) + References.clear(); return std::make_pair(References, FirstNonImportLine); } Index: cfe/trunk/unittests/Format/SortImportsTestJS.cpp === --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp @@ -190,40 +190,29 @@ } TEST_F(SortImportsTestJS, AffectedRange) {
Re: [PATCH] D23973: clang-format: [JS] handle default bindings in imports.
mprobst added a comment. In https://reviews.llvm.org/D23973#532801, @djasper wrote: > It would be helpful to have a before/after to review these patches. I assumed the test case was clear enough. Before, we couldn't parse default bindings at all, after, we do, and thus sort the imports in the test case. https://reviews.llvm.org/D23973 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r280486 - clang-format: [JS] handle default bindings in imports.
Author: mprobst Date: Fri Sep 2 09:06:32 2016 New Revision: 280486 URL: http://llvm.org/viewvc/llvm-project?rev=280486&view=rev Log: clang-format: [JS] handle default bindings in imports. Summary: Default imports appear outside of named bindings in curly braces: import A from 'a'; import A, {symbol} from 'a'; Reviewers: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D23973 Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp cfe/trunk/unittests/Format/SortImportsTestJS.cpp Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/SortJavaScriptImports.cpp?rev=280486&r1=280485&r2=280486&view=diff == --- cfe/trunk/lib/Format/SortJavaScriptImports.cpp (original) +++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp Fri Sep 2 09:06:32 2016 @@ -346,7 +346,6 @@ private: if (!parseModuleBindings(Keywords, Reference)) return false; -nextToken(); if (Current->is(Keywords.kw_from)) { // imports have a 'from' clause, exports might not. @@ -389,19 +388,28 @@ private: if (Current->isNot(tok::identifier)) return false; Reference.Prefix = Current->TokenText; +nextToken(); return true; } bool parseNamedBindings(const AdditionalKeywords &Keywords, JsModuleReference &Reference) { +if (Current->is(tok::identifier)) { + nextToken(); + if (Current->is(Keywords.kw_from)) +return true; + if (Current->isNot(tok::comma)) +return false; + nextToken(); // eat comma. +} if (Current->isNot(tok::l_brace)) return false; // {sym as alias, sym2 as ...} from '...'; -nextToken(); -while (true) { +while (Current->isNot(tok::r_brace)) { + nextToken(); if (Current->is(tok::r_brace)) -return true; +break; if (Current->isNot(tok::identifier)) return false; @@ -422,12 +430,11 @@ private: Symbol.Range.setEnd(Current->Tok.getLocation()); Reference.Symbols.push_back(Symbol); - if (Current->is(tok::r_brace)) -return true; - if (Current->isNot(tok::comma)) + if (!Current->isOneOf(tok::r_brace, tok::comma)) return false; - nextToken(); } +nextToken(); // consume r_brace +return true; } }; Modified: cfe/trunk/unittests/Format/SortImportsTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/SortImportsTestJS.cpp?rev=280486&r1=280485&r2=280486&view=diff == --- cfe/trunk/unittests/Format/SortImportsTestJS.cpp (original) +++ cfe/trunk/unittests/Format/SortImportsTestJS.cpp Fri Sep 2 09:06:32 2016 @@ -70,6 +70,26 @@ TEST_F(SortImportsTestJS, BasicSorting) "let x = 1;"); } +TEST_F(SortImportsTestJS, DefaultBinding) { + verifySort("import A from 'a';\n" + "import B from 'b';\n" + "\n" + "let x = 1;", + "import B from 'b';\n" + "import A from 'a';\n" + "let x = 1;"); +} + +TEST_F(SortImportsTestJS, DefaultAndNamedBinding) { + verifySort("import A, {a} from 'a';\n" + "import B, {b} from 'b';\n" + "\n" + "let x = 1;", + "import B, {b} from 'b';\n" + "import A, {a} from 'a';\n" + "let x = 1;"); +} + TEST_F(SortImportsTestJS, WrappedImportStatements) { verifySort("import {sym1, sym2} from 'a';\n" "import {sym} from 'b';\n" ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits