MyDeveloperDay created this revision.
MyDeveloperDay added reviewers: mprobst, krasimir, HazardyKnusperkeks, 
curdeius, owenpan.
MyDeveloperDay added projects: clang, clang-format.
MyDeveloperDay requested review of this revision.

https://github.com/llvm/llvm-project/issues/49858

The following issue highlights a problem where we cannot add a space between 
A|B when detecting a JSTypeOperator

This patch allows clang-format to be configured to support that (which seems to 
match most references I can find)

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types
https://flow.org/en/docs/types/intersections/

Fixes: #49858


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D117197

Files:
  clang/docs/ClangFormatStyleOptions.rst
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Format/Format.h
  clang/lib/Format/Format.cpp
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTest.cpp
  clang/unittests/Format/FormatTestJS.cpp

Index: clang/unittests/Format/FormatTestJS.cpp
===================================================================
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -1674,6 +1674,31 @@
   verifyFormat("export type X = {\n"
                "  a: Foo|Bar;\n"
                "};");
+
+  auto Style = getGoogleJSStyleWithColumns(60);
+  Style.SpacesInJavaScriptUnion = true;
+  verifyFormat("let x: A | B = A | B;", Style);
+  verifyFormat("let x?: A | B = A | B;", Style);
+  verifyFormat("let x: A & B | C = A & B;", Style);
+  verifyFormat("let x: Foo<A | B> = new Foo<A | B>();", Style);
+  verifyFormat("function(x: A | B): C & D {}", Style);
+  verifyFormat("function(x: A | B = A | B): C & D {}", Style);
+  verifyFormat("function x(path: number | string) {}", Style);
+  verifyFormat("function x(): string | number {}", Style);
+  verifyFormat("type Foo = Bar | Baz;", Style);
+  verifyFormat("type Foo = Bar<X> | Baz;", Style);
+  verifyFormat("type Foo = (Bar<X> | Baz);", Style);
+  verifyFormat("let x: Bar | Baz;", Style);
+  verifyFormat("let x: Bar<X> | Baz;", Style);
+  verifyFormat("let x: (Foo | Bar)[];", Style);
+  verifyFormat("type X = {\n"
+               "  a: Foo | Bar;\n"
+               "};",
+               Style);
+  verifyFormat("export type X = {\n"
+               "  a: Foo | Bar;\n"
+               "};",
+               Style);
 }
 
 TEST_F(FormatTestJS, UnionIntersectionTypesInObjectType) {
Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -18789,6 +18789,7 @@
   CHECK_PARSE_BOOL(SpaceInEmptyParentheses);
   CHECK_PARSE_BOOL(SpacesInContainerLiterals);
   CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses);
+  CHECK_PARSE_BOOL(SpacesInJavaScriptUnion);
   CHECK_PARSE_BOOL(SpaceAfterCStyleCast);
   CHECK_PARSE_BOOL(SpaceAfterTemplateKeyword);
   CHECK_PARSE_BOOL(SpaceAfterLogicalNot);
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3472,6 +3472,10 @@
     if (Right.is(tok::star) &&
         Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
       return false;
+    if (Left.is(TT_JsTypeOperator) && Right.isTypeOrIdentifier() ||
+        (Left.isTypeOrIdentifier() || Left.is(TT_TemplateCloser)) &&
+            Right.is(TT_JsTypeOperator))
+      return Style.SpacesInJavaScriptUnion;
     if (Right.isOneOf(tok::l_brace, tok::l_square) &&
         Left.isOneOf(Keywords.kw_function, Keywords.kw_yield,
                      Keywords.kw_extends, Keywords.kw_implements))
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -818,6 +818,7 @@
                    Style.SpacesInCStyleCastParentheses);
     IO.mapOptional("SpacesInLineCommentPrefix",
                    Style.SpacesInLineCommentPrefix);
+    IO.mapOptional("SpacesInJavaScriptUnion", Style.SpacesInJavaScriptUnion);
     IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
     IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
     IO.mapOptional("SpaceBeforeSquareBrackets",
@@ -1221,6 +1222,7 @@
   LLVMStyle.SpacesInContainerLiterals = true;
   LLVMStyle.SpacesInCStyleCastParentheses = false;
   LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u};
+  LLVMStyle.SpacesInJavaScriptUnion = false;
   LLVMStyle.SpaceAfterCStyleCast = false;
   LLVMStyle.SpaceAfterLogicalNot = false;
   LLVMStyle.SpaceAfterTemplateKeyword = true;
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -3614,6 +3614,15 @@
   /// \version 14
   SpacesInLineComment SpacesInLineCommentPrefix;
 
+  // If ``true``, spaces will be inserted before and after the ``|`` of
+  // a JavaScript/TypeScript union
+  /// \code
+  ///    true:                                  false:
+  ///    let x: A | B;   vs.                    let x: A|B;
+  /// \endcode
+  /// \version 14
+  bool SpacesInJavaScriptUnion;
+
   /// If ``true``, spaces will be inserted after ``(`` and before ``)``.
   /// \code
   ///    true:                                  false:
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -323,6 +323,9 @@
 - Option ``AfterOverloadedOperator`` has been added in ``SpaceBeforeParensOptions``
   to allow space between overloaded operator and opening parentheses.
 
+- Option ``SpacesInJavaScriptUnion`` has been added to allow spaces around
+  JavsScript Union and Intersection Type operators.
+
 libclang
 --------
 
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -3952,6 +3952,12 @@
      var arr = [ 1, 2, 3 ];         vs.     var arr = [1, 2, 3];
      f({a : 1, b : 2, c : 3});              f({a: 1, b: 2, c: 3});
 
+**SpacesInJavaScriptUnion** (``Boolean``) :versionbadge:`clang-format 14`
+  .. code-block:: c++
+
+     true:                                  false:
+     let x: A | B;   vs.                    let x: A|B;
+
 **SpacesInLineCommentPrefix** (``SpacesInLineComment``) :versionbadge:`clang-format 14`
   How many spaces are allowed at the start of a line comment. To disable the
   maximum set it to ``-1``, apart from that the maximum takes precedence
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to