Skip to content

Commit

Permalink
clang-format: [JS] handle semis in generic types.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mprobst committed Nov 25, 2017
1 parent 6c38ef9 commit e8e27ca
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 7 deletions.
17 changes: 10 additions & 7 deletions clang/lib/Format/UnwrappedLineParser.cpp
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions clang/unittests/Format/FormatTestJS.cpp
Expand Up @@ -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>;");
Expand Down

0 comments on commit e8e27ca

Please sign in to comment.