[PATCH] D150116: clang-format: [JS] support import/export type

2023-05-08 Thread Jan Kühle via Phabricator via cfe-commits
jankuehle created this revision.
jankuehle added a project: clang-format.
Herald added projects: All, clang.
Herald added a subscriber: cfe-commits.
Herald added reviewers: rymiel, HazardyKnusperkeks, owenpan, MyDeveloperDay.
jankuehle requested review of this revision.

Users can choose to only import/export the type of the symbol (not value nor 
namespace) by adding a `type` keyword, e.g.:

  import type {x} from 'y';
  import {type x} from 'y';
  export type {x};
  export {type x};

Previously, this was not handled and would:

- Terminate import sorting
- Remove the space before the curly bracket in `export type {`

With this change, both formatting and import sorting work as expected.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D150116

Files:
  clang/lib/Format/SortJavaScriptImports.cpp
  clang/lib/Format/UnwrappedLineParser.cpp
  clang/unittests/Format/FormatTestJS.cpp
  clang/unittests/Format/SortImportsTestJS.cpp

Index: clang/unittests/Format/SortImportsTestJS.cpp
===
--- clang/unittests/Format/SortImportsTestJS.cpp
+++ clang/unittests/Format/SortImportsTestJS.cpp
@@ -465,6 +465,46 @@
  "console.log(Z);\n");
 }
 
+TEST_F(SortImportsTestJS, ImportExportType) {
+  verifySort("import type {sym} from 'a';\n"
+ "import {type sym} from 'b';\n"
+ "import {sym} from 'c';\n"
+ "import type sym from 'd';\n"
+ "import type * as sym from 'e';\n"
+ "\n"
+ "let x = 1;",
+ "import {sym} from 'c';\n"
+ "import type {sym} from 'a';\n"
+ "import type * as sym from 'e';\n"
+ "import type sym from 'd';\n"
+ "import {type sym} from 'b';\n"
+ "let x = 1;");
+
+  // Symbols within import statement
+  verifySort("import {type sym1, type sym2 as a, sym3} from 'b';\n",
+ "import {type sym2 as a, type sym1, sym3} from 'b';\n");
+
+  // Merging
+  verifySort("import {X, type Z} from 'a';\n"
+ "import type {Y} from 'a';\n"
+ "\n"
+ "X + Y + Z;\n",
+ "import {X} from 'a';\n"
+ "import {type Z} from 'a';\n"
+ "import type {Y} from 'a';\n"
+ "\n"
+ "X + Y + Z;\n");
+
+  // Merging: empty imports
+  verifySort("import type {A} from 'foo';\n", "import type {} from 'foo';\n"
+  "import type {A} from 'foo';");
+
+  // Merging: exports
+  verifySort("export {A, type B} from 'foo';\n",
+ "export {A} from 'foo';\n"
+ "export   {type B} from 'foo';");
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -1476,6 +1476,17 @@
" export class Y {}");
 }
 
+TEST_F(FormatTestJS, ImportExportType) {
+  verifyFormat("import type {x, y} from 'y';\n"
+   "import type * as x from 'y';\n"
+   "import type x from 'y';\n"
+   "import {x, type yu, z} from 'y';\n");
+  verifyFormat("export type {x, y} from 'y';\n"
+   "export {x, type yu, z} from 'y';\n"
+   "export type {x, y};\n"
+   "export {x, type yu, z};\n");
+}
+
 TEST_F(FormatTestJS, ClosureStyleCasts) {
   verifyFormat("var x = /** @type {foo} */ (bar);");
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -4068,7 +4068,9 @@
   // parsing the structural element, i.e. the declaration or expression for
   // `export default`.
   if (!IsImport && !FormatTok->isOneOf(tok::l_brace, tok::star) &&
-  !FormatTok->isStringLiteral()) {
+  !FormatTok->isStringLiteral() &&
+  !(FormatTok->is(Keywords.kw_type) &&
+Tokens->peekNextToken()->isOneOf(tok::l_brace, tok::star))) {
 return;
   }
 
Index: clang/lib/Format/SortJavaScriptImports.cpp
===
--- clang/lib/Format/SortJavaScriptImports.cpp
+++ clang/lib/Format/SortJavaScriptImports.cpp
@@ -72,6 +72,7 @@
 struct JsModuleReference {
   bool FormattingOff = false;
   bool IsExport = false;
+  bool IsTypeOnly = false;
   // Module references are sorted into these categories, in order.
   enum ReferenceCategory {
 SIDE_EFFECT, // "import 'something';"
@@ -306,6 +307,7 @@
   if (Reference->Category == JsModuleReference::SIDE_EFFECT ||
   PreviousReference->Category == JsModuleReference::SIDE_EFFECT ||
   Reference->IsExport != PreviousReference->IsExport ||
+  Reference->IsTypeOnly != PreviousReference->IsTypeOnly ||
   !PreviousReference->Prefix.empty(

[PATCH] D150563: clang-format: [JS] terminate import sorting on `export type X = Y`

2023-05-15 Thread Jan Kühle via Phabricator via cfe-commits
jankuehle created this revision.
jankuehle added projects: clang, clang-format.
Herald added a project: All.
Herald added a subscriber: cfe-commits.
Herald added reviewers: rymiel, HazardyKnusperkeks, owenpan, MyDeveloperDay.
jankuehle requested review of this revision.

https://reviews.llvm.org/D150116 introduced a bug. `export type X = Y` was 
considered an export declaration and took part in import sorting. This is not 
correct. With this change `export type X = Y` properly terminates import 
sorting.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D150563

Files:
  clang/lib/Format/SortJavaScriptImports.cpp
  clang/unittests/Format/SortImportsTestJS.cpp


Index: clang/unittests/Format/SortImportsTestJS.cpp
===
--- clang/unittests/Format/SortImportsTestJS.cpp
+++ clang/unittests/Format/SortImportsTestJS.cpp
@@ -503,6 +503,15 @@
   verifySort("export {A, type B} from 'foo';\n",
  "export {A} from 'foo';\n"
  "export   {type B} from 'foo';");
+
+  // `export type X = Y;` should terminate import sorting. The following export
+  // statements should therefore not merge.
+  verifySort("export type A = B;\n"
+ "export {X};\n"
+ "export {Y};\n",
+ "export type A = B;\n"
+ "export {X};\n"
+ "export {Y};\n");
 }
 
 } // end namespace
Index: clang/lib/Format/SortJavaScriptImports.cpp
===
--- clang/lib/Format/SortJavaScriptImports.cpp
+++ clang/lib/Format/SortJavaScriptImports.cpp
@@ -517,7 +517,7 @@
 }
 
 // eat a potential "import X, " prefix.
-if (Current->is(tok::identifier)) {
+if (!Reference.IsExport && Current->is(tok::identifier)) {
   Reference.DefaultImport = Current->TokenText;
   nextToken();
   if (Current->is(Keywords.kw_from))


Index: clang/unittests/Format/SortImportsTestJS.cpp
===
--- clang/unittests/Format/SortImportsTestJS.cpp
+++ clang/unittests/Format/SortImportsTestJS.cpp
@@ -503,6 +503,15 @@
   verifySort("export {A, type B} from 'foo';\n",
  "export {A} from 'foo';\n"
  "export   {type B} from 'foo';");
+
+  // `export type X = Y;` should terminate import sorting. The following export
+  // statements should therefore not merge.
+  verifySort("export type A = B;\n"
+ "export {X};\n"
+ "export {Y};\n",
+ "export type A = B;\n"
+ "export {X};\n"
+ "export {Y};\n");
 }
 
 } // end namespace
Index: clang/lib/Format/SortJavaScriptImports.cpp
===
--- clang/lib/Format/SortJavaScriptImports.cpp
+++ clang/lib/Format/SortJavaScriptImports.cpp
@@ -517,7 +517,7 @@
 }
 
 // eat a potential "import X, " prefix.
-if (Current->is(tok::identifier)) {
+if (!Reference.IsExport && Current->is(tok::identifier)) {
   Reference.DefaultImport = Current->TokenText;
   nextToken();
   if (Current->is(Keywords.kw_from))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D108692: [clang-format] Support TypeScript override keyword

2021-08-25 Thread Jan Kühle via Phabricator via cfe-commits
jankuehle created this revision.
jankuehle requested review of this revision.
Herald added a project: clang.

TypeScript 4.3 added a new "override" keyword for class members. This
lets clang-format know about it, so it can format code using it
properly.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D108692

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/lib/Format/UnwrappedLineFormatter.cpp
  clang/lib/Format/UnwrappedLineParser.cpp
  clang/unittests/Format/FormatTestJS.cpp


Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -854,6 +854,26 @@
"}\n");
 }
 
+TEST_F(FormatTestJS, OverriddenMembers) {
+  verifyFormat(
+  "class C extends P {\n"
+  "  protected override "
+  "anOverlyLongPropertyNameSoLongItHasToGoInASeparateLineWhenOverriden:\n"
+  "  undefined;\n"
+  "}\n");
+  verifyFormat(
+  "class C extends P {\n"
+  "  protected override "
+  "anOverlyLongMethodNameSoLongItHasToGoInASeparateLineWhenOverriden() {\n"
+  "  }\n"
+  "}\n");
+  verifyFormat("class C extends P {\n"
+   "  protected override aMethodName() {}\n"
+   "}\n");
+}
+
 TEST_F(FormatTestJS, FunctionParametersTrailingComma) {
   verifyFormat("function trailingComma(\n"
"p1,\n"
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -962,8 +962,8 @@
   Keywords.kw_function, Keywords.kw_import, Keywords.kw_is,
   Keywords.kw_let, Keywords.kw_var, tok::kw_const,
   Keywords.kw_abstract, Keywords.kw_extends, 
Keywords.kw_implements,
-  Keywords.kw_instanceof, Keywords.kw_interface, 
Keywords.kw_throws,
-  Keywords.kw_from));
+  Keywords.kw_instanceof, Keywords.kw_interface,
+  Keywords.kw_override, Keywords.kw_throws, Keywords.kw_from));
 }
 
 static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords,
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -632,10 +632,11 @@
 FormatToken *RecordTok = Line.First;
 // Skip record modifiers.
 while (RecordTok->Next &&
-   RecordTok->isOneOf(
-   tok::kw_typedef, tok::kw_export, Keywords.kw_declare,
-   Keywords.kw_abstract, tok::kw_default, tok::kw_public,
-   tok::kw_private, tok::kw_protected, Keywords.kw_internal))
+   RecordTok->isOneOf(tok::kw_typedef, tok::kw_export,
+  Keywords.kw_declare, Keywords.kw_abstract,
+  tok::kw_default, Keywords.kw_override,
+  tok::kw_public, tok::kw_private,
+  tok::kw_protected, Keywords.kw_internal))
   RecordTok = RecordTok->Next;
 if (RecordTok &&
 RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3957,8 +3957,9 @@
 tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break,
 tok::kw_throw, Keywords.kw_interface, Keywords.kw_type,
 tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected,
-Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get,
-Keywords.kw_set, Keywords.kw_async, Keywords.kw_await))
+Keywords.kw_readonly, Keywords.kw_override, Keywords.kw_abstract,
+Keywords.kw_get, Keywords.kw_set, Keywords.kw_async,
+Keywords.kw_await))
   return false; // Otherwise automatic semicolon insertion would trigger.
 if (Right.NestingLevel == 0 &&
 (Left.Tok.getIdentifierInfo() ||
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -934,8 +934,8 @@
 // already initialized.
 JsExtraKeywords = std::unordered_set(
 {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from,
- kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly,
- kw_set, kw_type, kw_typeof, kw_var, kw_yield,
+ kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_override,
+ kw_readonly, kw_set, kw_type, kw_typeof, kw_var, kw_yield,
  // Keywords from the Java section.
  kw_abstra

[PATCH] D108692: [clang-format] Support TypeScript override keyword

2021-08-25 Thread Jan Kühle via Phabricator via cfe-commits
jankuehle added a comment.

Thank you for the amazingly quick review, krasimir. I don't have commit access. 
So it would be great, if you could commit this for me.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D108692/new/

https://reviews.llvm.org/D108692

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits