diff options
author | Martin Probst <martin@probst.io> | 2017-11-25 09:33:47 +0000 |
---|---|---|
committer | Martin Probst <martin@probst.io> | 2017-11-25 09:33:47 +0000 |
commit | e8e27ca866d89a40639c8592032ca21fdf4848bf (patch) | |
tree | a55dbf88ab7e8dc9a7d5683fb1bf1177737b0f43 /clang | |
parent | 6c38ef90fdd12917d9401bbaff95ebfc12a08491 (diff) | |
download | bcm5719-llvm-e8e27ca866d89a40639c8592032ca21fdf4848bf.tar.gz bcm5719-llvm-e8e27ca866d89a40639c8592032ca21fdf4848bf.zip |
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
llvm-svn: 318975
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Format/UnwrappedLineParser.cpp | 17 | ||||
-rw-r--r-- | clang/unittests/Format/FormatTestJS.cpp | 1 |
2 files changed, 11 insertions, 7 deletions
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 6dd922e4f26..b8608dcac9c 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -379,13 +379,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { 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. diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index cfdd4b375b6..187b50221d1 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -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, (a: number) => string>;"); |