From: Daniel Jasper Date: Mon, 13 Apr 2015 15:01:40 +0000 (+0000) Subject: clang-format: [JS] support optionality markers in JS types. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eb11bcb223c7907e38220f519c30b4a03a1ffc5f;p=clang clang-format: [JS] support optionality markers in JS types. Patch by Martin Probst. Thank you. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@234753 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 62c99326b6..bc14d4c539 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -49,6 +49,7 @@ enum TokenType { TT_InlineASMColon, TT_JavaAnnotation, TT_JsTypeColon, + TT_JsTypeOptionalQuestion, TT_LambdaArrow, TT_LambdaLSquare, TT_LeadingJavaAnnotation, diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 25c309a9f9..0ea67b288d 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -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)) diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index bfe62ecb95..eb587f2769 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -662,5 +662,13 @@ TEST_F(FormatTestJS, TypeArguments) { verifyFormat("class C extends D implements F, H {}"); } +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