r356449 - [clang-format] [JS] handle private members.

Martin Probst via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 19 05:28:41 PDT 2019


Author: mprobst
Date: Tue Mar 19 05:28:41 2019
New Revision: 356449

URL: http://llvm.org/viewvc/llvm-project?rev=356449&view=rev
Log:
[clang-format] [JS] handle private members.

Addresses PR40999 https://bugs.llvm.org/show_bug.cgi?id=40999

Private fields and methods in JavaScript would get incorrectly indented
(it sees them as preprocessor directives and hence left aligns them)

In this revision `#identifier` tokens `tok::hash->tok::identifier` are
merged into a single new token `tok::identifier` with the `#` contained
inside the TokenText.

Before:

```
class Example {
  pub = 1;

  static pub2 = "foo";
  static #priv2 = "bar";

  method() { this.#priv = 5; }

  static staticMethod() {
    switch (this.#priv) {
    case '1':
      break;
    }
  }

  this.#privateMethod(); // infinite loop
}

static #staticPrivateMethod() {}
}
```

After this fix the code will be correctly indented

```
class Example {
  pub = 1;
  #priv = 2;

  static pub2 = "foo";
  static #priv2 = "bar";

  method() { this.#priv = 5; }

  static staticMethod() {
    switch (this.#priv) {
    case '1':
      #priv = 3;
      break;
    }
  }

  #privateMethod() {
    this.#privateMethod(); // infinite loop
  }

  static #staticPrivateMethod() {}
}
```

NOTE: There might be some JavaScript code out there which uses the C
processor to preprocess .js files
http://www.nongnu.org/espresso/js-cpp.html. It's not clear how this
revision or even private fields and methods would interact.

Patch originally by MyDeveloperDays (thanks!).

Modified:
    cfe/trunk/lib/Format/FormatToken.h
    cfe/trunk/lib/Format/FormatTokenLexer.cpp
    cfe/trunk/lib/Format/FormatTokenLexer.h
    cfe/trunk/unittests/Format/FormatTestJS.cpp

Modified: cfe/trunk/lib/Format/FormatToken.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=356449&r1=356448&r2=356449&view=diff
==============================================================================
--- cfe/trunk/lib/Format/FormatToken.h (original)
+++ cfe/trunk/lib/Format/FormatToken.h Tue Mar 19 05:28:41 2019
@@ -60,6 +60,7 @@ namespace format {
   TYPE(JsExponentiationEqual)                                                  \
   TYPE(JsFatArrow)                                                             \
   TYPE(JsNonNullAssertion)                                                     \
+  TYPE(JsPrivateIdentifier)                                                    \
   TYPE(JsTypeColon)                                                            \
   TYPE(JsTypeOperator)                                                         \
   TYPE(JsTypeOptionalQuestion)                                                 \

Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.cpp?rev=356449&r1=356448&r2=356449&view=diff
==============================================================================
--- cfe/trunk/lib/Format/FormatTokenLexer.cpp (original)
+++ cfe/trunk/lib/Format/FormatTokenLexer.cpp Tue Mar 19 05:28:41 2019
@@ -95,6 +95,8 @@ void FormatTokenLexer::tryMergePreviousT
       Tokens.back()->Tok.setKind(tok::starequal);
       return;
     }
+    if (tryMergeJSPrivateIdentifier())
+      return;
   }
 
   if (Style.Language == FormatStyle::LK_Java) {
@@ -120,6 +122,25 @@ bool FormatTokenLexer::tryMergeNSStringL
   Tokens.erase(Tokens.end() - 1);
   return true;
 }
+
+bool FormatTokenLexer::tryMergeJSPrivateIdentifier() {
+  // Merges #idenfier into a single identifier with the text #identifier
+  // but the token tok::identifier.
+  if (Tokens.size() < 2)
+    return false;
+  auto &Hash = *(Tokens.end() - 2);
+  auto &Identifier = *(Tokens.end() - 1);
+  if (!Hash->is(tok::hash) || !Identifier->is(tok::identifier))
+    return false;
+  Hash->Tok.setKind(tok::identifier);
+  Hash->TokenText =
+      StringRef(Hash->TokenText.begin(),
+                Identifier->TokenText.end() - Hash->TokenText.begin());
+  Hash->ColumnWidth += Identifier->ColumnWidth;
+  Hash->Type = TT_JsPrivateIdentifier;
+  Tokens.erase(Tokens.end() - 1);
+  return true;
+}
 
 bool FormatTokenLexer::tryMergeLessLess() {
   // Merge X,less,less,Y into X,lessless,Y unless X or Y is less.

Modified: cfe/trunk/lib/Format/FormatTokenLexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.h?rev=356449&r1=356448&r2=356449&view=diff
==============================================================================
--- cfe/trunk/lib/Format/FormatTokenLexer.h (original)
+++ cfe/trunk/lib/Format/FormatTokenLexer.h Tue Mar 19 05:28:41 2019
@@ -48,6 +48,7 @@ private:
 
   bool tryMergeLessLess();
   bool tryMergeNSStringLiteral();
+  bool tryMergeJSPrivateIdentifier();
 
   bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType);
 

Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=356449&r1=356448&r2=356449&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTestJS.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestJS.cpp Tue Mar 19 05:28:41 2019
@@ -2334,5 +2334,27 @@ TEST_F(FormatTestJS, ConditionalTypes) {
       "                     never) extends((k: infer I) => void) ? I : never;");
 }
 
-} // end namespace tooling
+TEST_F(FormatTestJS, SupportPrivateFieldsAndMethods) {
+  verifyFormat("class Example {\n"
+               "  pub = 1;\n"
+               "  #priv = 2;\n"
+               "  static pub2 = 'foo';\n"
+               "  static #priv2 = 'bar';\n"
+               "  method() {\n"
+               "    this.#priv = 5;\n"
+               "  }\n"
+               "  static staticMethod() {\n"
+               "    switch (this.#priv) {\n"
+               "      case '1':\n"
+               "        #priv = 3;\n"
+               "        break;\n"
+               "    }\n"
+               "  }\n"
+               "  #privateMethod() {\n"
+               "    this.#privateMethod();  // infinite loop\n"
+               "  }\n"
+               "  static #staticPrivateMethod() {}\n");
+}
+
+} // namespace format
 } // end namespace clang




More information about the cfe-commits mailing list