[clang] e8c5fea - [clang-format] Special handling of spaces for C# code

Jonathan Coe via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 26 07:34:42 PST 2020


Author: Jonathan Coe
Date: 2020-02-26T15:27:03Z
New Revision: e8c5fea243ce30640ec9707fabdb635a49b3153c

URL: https://github.com/llvm/llvm-project/commit/e8c5fea243ce30640ec9707fabdb635a49b3153c
DIFF: https://github.com/llvm/llvm-project/commit/e8c5fea243ce30640ec9707fabdb635a49b3153c.diff

LOG: [clang-format] Special handling of spaces for C# code

Summary:
Ensure that there are spaces around braces '{', '}'.

Ensure that there is a space before and after '=>'.

Ensure that 'async' and 'when' are considered as keywords when inserting spaces.

Reviewers: krasimir, MyDeveloperDay

Reviewed By: krasimir

Tags: #clang-format

Differential Revision: https://reviews.llvm.org/D75129

Added: 
    

Modified: 
    clang/lib/Format/FormatToken.h
    clang/lib/Format/TokenAnnotator.cpp
    clang/unittests/Format/FormatTestCSharp.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index dc68cbc79734..6bbfdcf37f93 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -771,6 +771,7 @@ struct AdditionalKeywords {
     kw_unchecked = &IdentTable.get("unchecked");
     kw_unsafe = &IdentTable.get("unsafe");
     kw_ushort = &IdentTable.get("ushort");
+    kw_when = &IdentTable.get("when");
 
     // Keep this at the end of the constructor to make sure everything here
     // is
@@ -787,7 +788,7 @@ struct AdditionalKeywords {
          kw_fixed, kw_foreach, kw_implicit, kw_in, kw_interface, kw_internal,
          kw_is, kw_lock, kw_null, kw_object, kw_out, kw_override, kw_params,
          kw_readonly, kw_ref, kw_string, kw_stackalloc, kw_sbyte, kw_sealed,
-         kw_uint, kw_ulong, kw_unchecked, kw_unsafe, kw_ushort,
+         kw_uint, kw_ulong, kw_unchecked, kw_unsafe, kw_ushort, kw_when,
          // Keywords from the JavaScript section.
          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,
@@ -891,6 +892,7 @@ struct AdditionalKeywords {
   IdentifierInfo *kw_unchecked;
   IdentifierInfo *kw_unsafe;
   IdentifierInfo *kw_ushort;
+  IdentifierInfo *kw_when;
 
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c false if it is a keyword or a pseudo keyword.

diff  --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index d71c4f470378..04b20599638d 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -2870,21 +2870,34 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
     if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
       return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin();
   } else if (Style.isCSharp()) {
+    // Require spaces around '{' and  before '}' unless they appear in
+    // interpolated strings. Interpolated strings are merged into a single token
+    // so cannot have spaces inserted by this function.
+
+    // Space before { (including space within '{ {').
+    if (Right.is(tok::l_brace))
+      return true;
+
+    // Spaces inside braces.
+    if (Left.is(tok::l_brace) && Right.isNot(tok::r_brace))
+      return true;
+
+    if (Left.isNot(tok::l_brace) && Right.is(tok::r_brace))
+      return true;
+
+    // Spaces around '=>'.
+    if (Left.is(TT_JsFatArrow) || Right.is(TT_JsFatArrow))
+      return true;
+
     // space between type and variable e.g. Dictionary<string,string> foo;
     if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
       return true;
+
     // space between keywords and paren e.g. "using ("
     if (Right.is(tok::l_paren))
-      if (Left.is(tok::kw_using))
+      if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
         return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements ||
                spaceRequiredBeforeParens(Right);
-    // space between ']' and '{'
-    if (Left.is(tok::r_square) && Right.is(tok::l_brace))
-      return true;
-    // space before '{' in "new MyType {"
-    if (Right.is(tok::l_brace) && Left.Previous &&
-        Left.Previous->is(tok::kw_new))
-      return true;
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
     if (Left.is(TT_JsFatArrow))
       return true;

diff  --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp
index 68a8e9fefe2d..3bdaf3d5a9f3 100644
--- a/clang/unittests/Format/FormatTestCSharp.cpp
+++ b/clang/unittests/Format/FormatTestCSharp.cpp
@@ -525,11 +525,11 @@ Shape[] shapes = new[] {
 
   // Omitted final `,`s will change the formatting.
   verifyFormat(R"(//
-Shape[] shapes = new[] {new Circle {Radius = 2.7281, Colour = Colours.Red},
-                        new Square {
-                            Side = 101.1,
-                            Colour = Colours.Yellow,
-                        }};)",
+Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
+                         new Square {
+                             Side = 101.1,
+                             Colour = Colours.Yellow,
+                         } };)",
                Style);
 }
 
@@ -575,5 +575,27 @@ public string Name {
                Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpSpaces) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  Style.SpaceBeforeSquareBrackets = false;
+  Style.SpacesInSquareBrackets = false;
+  Style.SpaceBeforeCpp11BracedList = true;
+  Style.Cpp11BracedListStyle = false;
+  Style.SpacesInContainerLiterals = false;
+
+  verifyFormat(R"(new Car { "Door", 0.1 })", Style);
+  verifyFormat(R"(new Car { 0.1, "Door" })", Style);
+  verifyFormat(R"(new string[] { "A" })", Style);
+  verifyFormat(R"(new string[] {})", Style);
+  verifyFormat(R"(new Car { someVariableName })", Style);
+  verifyFormat(R"(new Car { someVariableName })", Style);
+  verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)",
+               Style);
+  verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style);
+  verifyFormat(R"(bool[] xs = { true, true };)", Style);
+  verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
+  verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
+}
+
 } // namespace format
 } // end namespace clang


        


More information about the cfe-commits mailing list