MyDeveloperDay created this revision.
MyDeveloperDay added reviewers: djasper, klimek, JonasToth, reuk, krasimir.
MyDeveloperDay added a project: clang-tools-extra.

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

Private fields and methods  in javasceipt 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

  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() {}
  }

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,  Its not 
clear how this revision or even private fields and methods would interact.


https://reviews.llvm.org/D59292

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Format/FormatToken.h
  clang/lib/Format/FormatTokenLexer.cpp
  clang/lib/Format/FormatTokenLexer.h
  clang/unittests/Format/FormatTestJS.cpp

Index: clang/unittests/Format/FormatTestJS.cpp
===================================================================
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2328,5 +2328,27 @@
       "                     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
Index: clang/lib/Format/FormatTokenLexer.h
===================================================================
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -48,6 +48,7 @@
 
   bool tryMergeLessLess();
   bool tryMergeNSStringLiteral();
+  bool tryMergeJSPrivateIdentifier();
 
   bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType);
 
Index: clang/lib/Format/FormatTokenLexer.cpp
===================================================================
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -95,6 +95,8 @@
       Tokens.back()->Tok.setKind(tok::starequal);
       return;
     }
+    if (tryMergeJSPrivateIdentifier())
+      return;
   }
 
   if (Style.Language == FormatStyle::LK_Java) {
@@ -121,6 +123,25 @@
   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.
   if (Tokens.size() < 3)
Index: clang/lib/Format/FormatToken.h
===================================================================
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -63,6 +63,7 @@
   TYPE(JsTypeColon)                                                            \
   TYPE(JsTypeOperator)                                                         \
   TYPE(JsTypeOptionalQuestion)                                                 \
+  TYPE(JsPrivateIdentifier)                                                    \
   TYPE(LambdaArrow)                                                            \
   TYPE(LambdaLSquare)                                                          \
   TYPE(LeadingJavaAnnotation)                                                  \
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -171,7 +171,7 @@
 ------------
 
 
-- ...
+- Add support for correct indenting of private fields and methods in Javascript.
 
 libclang
 --------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to