Commit a7638d38 authored by Martin Probst's avatar Martin Probst
Browse files

clang-format: [JS] support null operators.

Summary:
JavaScript / TypeScript is adding two new operators: the null
propagating operator `?.` and the nullish coalescing operator `??`.

    const x = foo ?? 'default';
    const z = foo?.bar?.baz;

This change adds support to lex and format both.

Reviewers: krasimir

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D69971
parent 48b7068b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ namespace format {
  TYPE(JsExponentiationEqual)                                                  \
  TYPE(JsFatArrow)                                                             \
  TYPE(JsNonNullAssertion)                                                     \
  TYPE(JsNullishCoalescingOperator)                                            \
  TYPE(JsNullPropagatingOperator)                                              \
  TYPE(JsPrivateIdentifier)                                                    \
  TYPE(JsTypeColon)                                                            \
  TYPE(JsTypeOperator)                                                         \
+12 −0
Original line number Diff line number Diff line
@@ -100,6 +100,10 @@ void FormatTokenLexer::tryMergePreviousTokens() {
    static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star};
    static const tok::TokenKind JSExponentiationEqual[] = {tok::star,
                                                           tok::starequal};
    static const tok::TokenKind JSNullPropagatingOperator[] = {tok::question,
                                                               tok::period};
    static const tok::TokenKind JSNullishOperator[] = {tok::question,
                                                       tok::question};

    // FIXME: Investigate what token type gives the correct operator priority.
    if (tryMergeTokens(JSIdentity, TT_BinaryOperator))
@@ -116,6 +120,14 @@ void FormatTokenLexer::tryMergePreviousTokens() {
      Tokens.back()->Tok.setKind(tok::starequal);
      return;
    }
    if (tryMergeTokens(JSNullishOperator, TT_JsNullishCoalescingOperator))
      return;
    if (tryMergeTokens(JSNullPropagatingOperator,
                       TT_JsNullPropagatingOperator)) {
      // Treat like a regular "." access.
      Tokens.back()->Tok.setKind(tok::period);
      return;
    }
    if (tryMergeJSPrivateIdentifier())
      return;
  }
+10 −0
Original line number Diff line number Diff line
@@ -2222,6 +2222,16 @@ TEST_F(FormatTestJS, NonNullAssertionOperator) {
  verifyFormat("return !!x;\n");
}

TEST_F(FormatTestJS, NullPropagatingOperator) {
  verifyFormat("let x = foo?.bar?.baz();\n");
  verifyFormat("let x = foo?.(foo);\n");
  verifyFormat("let x = foo?.['arr'];\n");
}

TEST_F(FormatTestJS, NullishCoalescingOperator) {
  verifyFormat("const val = something ?? 'some other default';\n");
}

TEST_F(FormatTestJS, Conditional) {
  verifyFormat("y = x ? 1 : 2;");
  verifyFormat("x ? 1 : 2;");