]> granicus.if.org Git - clang/commitdiff
clang-format: [JS] support optionality markers in JS types.
authorDaniel Jasper <djasper@google.com>
Mon, 13 Apr 2015 15:01:40 +0000 (15:01 +0000)
committerDaniel Jasper <djasper@google.com>
Mon, 13 Apr 2015 15:01:40 +0000 (15:01 +0000)
Patch by Martin Probst. Thank you.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@234753 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Format/FormatToken.h
lib/Format/TokenAnnotator.cpp
unittests/Format/FormatTestJS.cpp

index 62c99326b698bf8ef0faad72990f0b2d98e4b418..bc14d4c5392dbb5b76ffb4d0e625462f6e562b24 100644 (file)
@@ -49,6 +49,7 @@ enum TokenType {
   TT_InlineASMColon,
   TT_JavaAnnotation,
   TT_JsTypeColon,
+  TT_JsTypeOptionalQuestion,
   TT_LambdaArrow,
   TT_LambdaLSquare,
   TT_LeadingJavaAnnotation,
index 25c309a9f99e645d013e78fd077c503c91b065ea..0ea67b288d049351c89f10bc5caf4d0de69122b1 100644 (file)
@@ -409,6 +409,15 @@ private:
       if (!Tok->Previous)
         return false;
       // Colons from ?: are handled in parseConditional().
+      if (Style.Language == FormatStyle::LK_JavaScript) {
+        if (Contexts.back().ColonIsForRangeExpr ||
+            (Contexts.size() == 1 &&
+             !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) ||
+            Contexts.back().ContextKind == tok::l_paren) {
+          Tok->Type = TT_JsTypeColon;
+          break;
+        }
+      }
       if (Contexts.back().ColonIsDictLiteral) {
         Tok->Type = TT_DictLiteral;
       } else if (Contexts.back().ColonIsObjCMethodExpr ||
@@ -422,16 +431,12 @@ private:
         if (!Contexts.back().FirstObjCSelectorName)
           Contexts.back().FirstObjCSelectorName = Tok->Previous;
       } else if (Contexts.back().ColonIsForRangeExpr) {
-        Tok->Type = Style.Language == FormatStyle::LK_JavaScript
-                        ? TT_JsTypeColon
-                        : TT_RangeBasedForLoopColon;
+        Tok->Type = TT_RangeBasedForLoopColon;
       } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
         Tok->Type = TT_BitFieldColon;
       } else if (Contexts.size() == 1 &&
                  !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) {
-        if (Style.Language == FormatStyle::LK_JavaScript)
-          Tok->Type = TT_JsTypeColon;
-        else if (Tok->Previous->is(tok::r_paren))
+        if (Tok->Previous->is(tok::r_paren))
           Tok->Type = TT_CtorInitializerColon;
         else
           Tok->Type = TT_InheritanceColon;
@@ -441,9 +446,7 @@ private:
         // the colon are passed as macro arguments.
         Tok->Type = TT_ObjCMethodExpr;
       } else if (Contexts.back().ContextKind == tok::l_paren) {
-        Tok->Type = Style.Language == FormatStyle::LK_JavaScript
-                        ? TT_JsTypeColon
-                        : TT_InlineASMColon;
+        Tok->Type = TT_InlineASMColon;
       }
       break;
     case tok::kw_if:
@@ -516,6 +519,15 @@ private:
       }
       break;
     case tok::question:
+      if (Style.Language == FormatStyle::LK_JavaScript && Tok->Next &&
+          Tok->Next->isOneOf(tok::colon, tok::semi, tok::r_paren,
+                             tok::r_brace)) {
+        // Question marks before semicolons, colons, commas, etc. indicate
+        // optional types (fields, parameters), e.g.
+        // `function(x?: string, y?) {...}` or `class X {y?;}`
+        Tok->Type = TT_JsTypeOptionalQuestion;
+        break;
+      }
       parseConditional();
       break;
     case tok::kw_template:
@@ -1774,7 +1786,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
     if (Left.is(Keywords.kw_var))
       return true;
-    if (Right.is(TT_JsTypeColon))
+    if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion))
       return false;
     if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) &&
         Line.First->isOneOf(Keywords.kw_import, tok::kw_export))
index bfe62ecb956a7f9b75162405034de94f2efdaf5e..eb587f27694e3a50061344e4dd7daf5467921894 100644 (file)
@@ -662,5 +662,13 @@ TEST_F(FormatTestJS, TypeArguments) {
   verifyFormat("class C extends D<E> implements F<G>, H<I> {}");
 }
 
+TEST_F(FormatTestJS, OptionalTypes) {
+  verifyFormat("function x(a?: b, c?, d?) {\n}");
+  verifyFormat("class X {\n"
+               "  y?: z;\n"
+               "  z?;\n"
+               "}");
+}
+
 } // end namespace tooling
 } // end namespace clang