r257255 - clang-format: [JS] Support semicolons in TypeScript's TypeMemberLists.

Daniel Jasper via cfe-commits cfe-commits at lists.llvm.org
Sat Jan 9 07:56:29 PST 2016


Author: djasper
Date: Sat Jan  9 09:56:28 2016
New Revision: 257255

URL: http://llvm.org/viewvc/llvm-project?rev=257255&view=rev
Log:
clang-format: [JS] Support semicolons in TypeScript's TypeMemberLists.

Before:
  var x: {
    a: string;
    b: number;
  }
  = {};

After:
  var x: {a: string; b: number;} = {};

Modified:
    cfe/trunk/lib/Format/UnwrappedLineParser.cpp
    cfe/trunk/lib/Format/UnwrappedLineParser.h
    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=257255&r1=257254&r2=257255&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original)
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Sat Jan  9 09:56:28 2016
@@ -315,6 +315,7 @@ void UnwrappedLineParser::calculateBrace
   // definitions, too.
   unsigned StoredPosition = Tokens->getPosition();
   FormatToken *Tok = FormatTok;
+  const FormatToken *PrevTok = getPreviousToken();
   // Keep a stack of positions of lbrace tokens. We will
   // update information about whether an lbrace starts a
   // braced init list or a different block during the loop.
@@ -331,47 +332,53 @@ void UnwrappedLineParser::calculateBrace
 
     switch (Tok->Tok.getKind()) {
     case tok::l_brace:
-      Tok->BlockKind = BK_Unknown;
+      if (Style.Language == FormatStyle::LK_JavaScript && PrevTok &&
+          PrevTok->is(tok::colon))
+        // In TypeScript's TypeMemberLists, there can be semicolons between the
+        // individual members.
+        Tok->BlockKind = BK_BracedInit;
+      else
+        Tok->BlockKind = BK_Unknown;
       LBraceStack.push_back(Tok);
       break;
     case tok::r_brace:
-      if (!LBraceStack.empty()) {
-        if (LBraceStack.back()->BlockKind == BK_Unknown) {
-          bool ProbablyBracedList = false;
-          if (Style.Language == FormatStyle::LK_Proto) {
-            ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
-          } else {
-            // Using OriginalColumn to distinguish between ObjC methods and
-            // binary operators is a bit hacky.
-            bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
-                                    NextTok->OriginalColumn == 0;
-
-            // If there is a comma, semicolon or right paren after the closing
-            // brace, we assume this is a braced initializer list.  Note that
-            // regardless how we mark inner braces here, we will overwrite the
-            // 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).
-            //
-            // We exclude + and - as they can be ObjC visibility modifiers.
-            ProbablyBracedList =
-                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) ||
-                (NextTok->is(tok::semi) &&
-                 (!ExpectClassBody || LBraceStack.size() != 1)) ||
-                (NextTok->isBinaryOperator() && !NextIsObjCMethod);
-          }
-          if (ProbablyBracedList) {
-            Tok->BlockKind = BK_BracedInit;
-            LBraceStack.back()->BlockKind = BK_BracedInit;
-          } else {
-            Tok->BlockKind = BK_Block;
-            LBraceStack.back()->BlockKind = BK_Block;
-          }
+      if (LBraceStack.empty())
+        break;
+      if (LBraceStack.back()->BlockKind == BK_Unknown) {
+        bool ProbablyBracedList = false;
+        if (Style.Language == FormatStyle::LK_Proto) {
+          ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
+        } else {
+          // Using OriginalColumn to distinguish between ObjC methods and
+          // binary operators is a bit hacky.
+          bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
+                                  NextTok->OriginalColumn == 0;
+
+          // If there is a comma, semicolon or right paren after the closing
+          // brace, we assume this is a braced initializer list.  Note that
+          // regardless how we mark inner braces here, we will overwrite the
+          // 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).
+          //
+          // We exclude + and - as they can be ObjC visibility modifiers.
+          ProbablyBracedList =
+              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) ||
+              (NextTok->is(tok::semi) &&
+               (!ExpectClassBody || LBraceStack.size() != 1)) ||
+              (NextTok->isBinaryOperator() && !NextIsObjCMethod);
+        }
+        if (ProbablyBracedList) {
+          Tok->BlockKind = BK_BracedInit;
+          LBraceStack.back()->BlockKind = BK_BracedInit;
+        } else {
+          Tok->BlockKind = BK_Block;
+          LBraceStack.back()->BlockKind = BK_Block;
         }
-        LBraceStack.pop_back();
       }
+      LBraceStack.pop_back();
       break;
     case tok::at:
     case tok::semi:
@@ -381,14 +388,16 @@ void UnwrappedLineParser::calculateBrace
     case tok::kw_switch:
     case tok::kw_try:
     case tok::kw___try:
-      if (!LBraceStack.empty())
+      if (!LBraceStack.empty() && LBraceStack.back()->BlockKind == BK_Unknown)
         LBraceStack.back()->BlockKind = BK_Block;
       break;
     default:
       break;
     }
+    PrevTok = Tok;
     Tok = NextTok;
   } while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty());
+
   // Assume other blocks for all unclosed opening braces.
   for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) {
     if (LBraceStack[i]->BlockKind == BK_Unknown)
@@ -988,13 +997,11 @@ bool UnwrappedLineParser::tryToParseLamb
     nextToken();
     return false;
   }
-  // FIXME: This is a dirty way to access the previous token. Find a better
-  // solution.
-  if (!Line->Tokens.empty() &&
-      (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator,
-                                        tok::kw_new, tok::kw_delete) ||
-       Line->Tokens.back().Tok->closesScope() ||
-       Line->Tokens.back().Tok->isSimpleTypeSpecifier())) {
+  const FormatToken* Previous = getPreviousToken();
+  if (Previous &&
+      (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
+                         tok::kw_delete) ||
+       Previous->closesScope() || Previous->isSimpleTypeSpecifier())) {
     nextToken();
     return false;
   }
@@ -1176,6 +1183,14 @@ bool UnwrappedLineParser::parseBracedLis
       nextToken();
       return !HasError;
     case tok::semi:
+      // JavaScript (or more precisely TypeScript) can have semicolons in braced
+      // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
+      // used for error recovery if we have otherwise determined that this is
+      // a braced list.
+      if (Style.Language == FormatStyle::LK_JavaScript) {
+        nextToken();
+        break;
+      }
       HasError = true;
       if (!ContinueOnSemicolons)
         return !HasError;
@@ -1878,6 +1893,14 @@ void UnwrappedLineParser::nextToken() {
   readToken();
 }
 
+const FormatToken *UnwrappedLineParser::getPreviousToken() {
+  // FIXME: This is a dirty way to access the previous token. Find a better
+  // solution.
+  if (!Line || Line->Tokens.empty())
+    return nullptr;
+  return Line->Tokens.back().Tok;
+}
+
 void UnwrappedLineParser::readToken() {
   bool CommentsInCurrentLine = true;
   do {

Modified: cfe/trunk/lib/Format/UnwrappedLineParser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.h?rev=257255&r1=257254&r2=257255&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineParser.h (original)
+++ cfe/trunk/lib/Format/UnwrappedLineParser.h Sat Jan  9 09:56:28 2016
@@ -110,6 +110,7 @@ private:
   void addUnwrappedLine();
   bool eof() const;
   void nextToken();
+  const FormatToken *getPreviousToken();
   void readToken();
   void flushComments(bool NewlineBeforeNext);
   void pushToken(FormatToken *Tok);

Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=257255&r1=257254&r2=257255&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTestJS.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sat Jan  9 09:56:28 2016
@@ -731,10 +731,14 @@ TEST_F(FormatTestJS, RegexLiteralExample
 
 TEST_F(FormatTestJS, TypeAnnotations) {
   verifyFormat("var x: string;");
+  verifyFormat("var x: {a: string; b: number;} = {};");
   verifyFormat("function x(): string {\n  return 'x';\n}");
   verifyFormat("function x(): {x: string} {\n  return {x: 'x'};\n}");
   verifyFormat("function x(y: string): string {\n  return 'x';\n}");
   verifyFormat("for (var y: string in x) {\n  x();\n}");
+  verifyFormat("function x(y: {a?: number;} = {}): number {\n"
+               "  return 12;\n"
+               "}");
   verifyFormat("((a: string, b: number): string => a + b);");
   verifyFormat("var x: (y: number) => string;");
   verifyFormat("var x: P<string, (a: number) => string>;");
@@ -764,6 +768,10 @@ TEST_F(FormatTestJS, ClassDeclarations)
   verifyFormat("foo = class {\n"
                "  constructor() {}\n"
                "};");
+  verifyFormat("class C {\n"
+               "  x: {y: Z;} = {};\n"
+               "  private y: {y: Z;} = {};\n"
+               "}");
 
   // ':' is not a type declaration here.
   verifyFormat("class X {\n"




More information about the cfe-commits mailing list