MyDeveloperDay updated this revision to Diff 515060.
MyDeveloperDay added a comment.

Adds additional options to give us much greater control over how we format C# 
properties especially auto properties

(Submitting this for safe keeping, I need to try and minimize the if 
expression, I'm sure it could be simplified into a few less clauses)


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

https://reviews.llvm.org/D148467

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/lib/Format/UnwrappedLineParser.cpp
  clang/unittests/Format/FormatTestCSharp.cpp

Index: clang/unittests/Format/FormatTestCSharp.cpp
===================================================================
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -42,14 +42,17 @@
     return Style;
   }
 
-  static void verifyFormat(
-      llvm::StringRef Code,
+  static void _verifyFormat(
+      const char *File, int Line, llvm::StringRef Code,
       const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
+    ::testing::ScopedTrace t(File, Line, ::testing::Message() << Code.str());
     EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
   }
 };
 
+#define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)
+
 TEST_F(FormatTestCSharp, CSharpClass) {
   verifyFormat("public class SomeClass\n"
                "{\n"
@@ -1612,5 +1615,424 @@
   EXPECT_NE("", format("int where b <")); // reduced from crasher
 }
 
+TEST_F(FormatTestCSharp, PropertyWrapping) {
+  FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
+
+  Style.BraceWrapping.AfterCSharpProperty = false;
+  Style.AllowShortCSharpPropertiesOnASingleLine = true;
+  Style.AlwaysBreakBetweenShortCSharpProperties = false;
+  Style.BraceWrapping.AfterFunction = true;
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo { set; get; }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo { get; set; }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo { get; init; }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        set {\n"
+               "            val = value;\n"
+               "        }\n"
+               "        get {\n"
+               "            return value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        init {\n"
+               "            val = value;\n"
+               "        }\n"
+               "        get {\n"
+               "            return value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        get;\n"
+               "        set {\n"
+               "            val = value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        get;\n"
+               "        init {\n"
+               "            val = value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo { private set; get; }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo { set; public get; }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        get;\n"
+               "        public init {\n"
+               "            val = value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        public init {\n"
+               "            val = value;\n"
+               "        }\n"
+               "        get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        public get;\n"
+               "        init {\n"
+               "            val = value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Foo\n"
+               "    {\n"
+               "        get;\n"
+               "        public init {\n"
+               "            val = value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+
+  Style.BraceWrapping.AfterCSharpProperty = true;
+  Style.AllowShortCSharpPropertiesOnASingleLine = false;
+  Style.AlwaysBreakBetweenShortCSharpProperties = true;
+  Style.BraceWrapping.AfterFunction = true;
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        set;\n"
+               "        get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        get;\n"
+               "        set;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        get;\n"
+               "        init;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        set\n"
+               "        {\n"
+               "            val = value;\n"
+               "        }\n"
+               "        get\n"
+               "        {\n"
+               "            return value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        init\n"
+               "        {\n"
+               "            val = value;\n"
+               "        }\n"
+               "        get\n"
+               "        {\n"
+               "            return value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        get;\n"
+               "        set\n"
+               "        {\n"
+               "            val = value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        get;\n"
+               "        init\n"
+               "        {\n"
+               "            val = value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        private set;\n"
+               "        get;\n"
+               "    }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        set;\n"
+               "        internal get;\n"
+               "    }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar6\n"
+               "    {\n"
+               "        set;\n"
+               "        internal get\n"
+               "        {\n"
+               "            return value;\n"
+               "        };\n"
+               "    }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar5\n"
+               "    {\n"
+               "        internal get\n"
+               "        {\n"
+               "            return value;\n"
+               "        };\n"
+               "        set;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        internal set;\n"
+               "        get\n"
+               "        {\n"
+               "            return value;\n"
+               "        };\n"
+               "    }\n"
+               "}",
+               Style);
+
+  Style.BraceWrapping.AfterCSharpProperty = true;
+  Style.AllowShortCSharpPropertiesOnASingleLine = false;
+  Style.AlwaysBreakBetweenShortCSharpProperties = false;
+  Style.BraceWrapping.AfterFunction = true;
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        set; get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        get; set;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        init; get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        internal set; get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        set; protected get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        set;\n"
+               "        protected get\n"
+               "        {\n"
+               "            return value;\n"
+               "        }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar\n"
+               "    {\n"
+               "        public get\n"
+               "        {\n"
+               "            return value;\n"
+               "        }\n"
+               "        set;\n"
+               "    }\n"
+               "}",
+               Style);
+
+  Style.BraceWrapping.AfterCSharpProperty = false;
+  Style.AllowShortCSharpPropertiesOnASingleLine = false;
+  Style.AlwaysBreakBetweenShortCSharpProperties = false;
+  Style.BraceWrapping.AfterFunction = false;
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar1 {\n"
+               "        set; get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar1 {\n"
+               "        get; set;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar1 {\n"
+               "        init; get;\n"
+               "    }\n"
+               "}",
+               Style);
+
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar2 {\n"
+               "        public set; get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar2 {\n"
+               "        set; private get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar3 {\n"
+               "        set { value = 123 }\n"
+               "        get;\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar4 {\n"
+               "        get;\n"
+               "        set { value = 123 }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar4 {\n"
+               "        private get;\n"
+               "        set { value = 123 }\n"
+               "    }\n"
+               "}",
+               Style);
+  verifyFormat("class A\n"
+               "{\n"
+               "    string Bar4 {\n"
+               "        get;\n"
+               "        private set { value = 123 }\n"
+               "    }\n"
+               "}",
+               Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/UnwrappedLineParser.cpp
===================================================================
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -2073,8 +2073,22 @@
   // Try to parse the property accessor:
   // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
   Tokens->setPosition(StoredPosition);
-  if (!IsTrivialPropertyAccessor && Style.BraceWrapping.AfterFunction)
+  if ((!IsTrivialPropertyAccessor &&
+       Style.AllowShortCSharpPropertiesOnASingleLine) &&
+      Style.BraceWrapping.AfterFunction) {
     addUnwrappedLine();
+  }
+
+  // Handle non short property on a single line
+  // string Foo
+  // {
+  //     set;get;
+  // }
+  if (!Style.AllowShortCSharpPropertiesOnASingleLine &&
+      Style.BraceWrapping.AfterFunction) {
+    addUnwrappedLine();
+  }
+
   nextToken();
   do {
     switch (FormatTok->Tok.getKind()) {
@@ -2087,6 +2101,16 @@
       }
       addUnwrappedLine();
       return true;
+    case tok::semi:
+      if (!IsTrivialPropertyAccessor) {
+        ++Line->Level;
+        nextToken();
+        addUnwrappedLine();
+        --Line->Level;
+        break;
+      }
+      nextToken();
+      break;
     case tok::l_brace:
       ++Line->Level;
       parseBlock(/*MustBeDeclaration=*/true);
@@ -2107,12 +2131,24 @@
       nextToken();
       break;
     default:
-      if (FormatTok->isOneOf(Keywords.kw_get, Keywords.kw_init,
-                             Keywords.kw_set) &&
+      bool WrappedAlready = false;
+      if (FormatTok->isOneOf(Keywords.kw_internal, tok::kw_private,
+                             tok::kw_public, tok::kw_protected) &&
           !IsTrivialPropertyAccessor) {
         // Non-trivial get/set needs to be on its own line.
         addUnwrappedLine();
+        nextToken();
+        WrappedAlready = true;
       }
+      if (FormatTok->isOneOf(Keywords.kw_get, Keywords.kw_init, Keywords.kw_set,
+                             Keywords.kw_internal, tok::kw_private,
+                             tok::kw_public, tok::kw_protected) &&
+          !IsTrivialPropertyAccessor) {
+        // Non-trivial get/set needs to be on its own line.
+        if (!WrappedAlready)
+          addUnwrappedLine();
+      }
+
       nextToken();
     }
   } while (!eof());
@@ -2176,8 +2212,8 @@
     // Specialization of a template with an integer parameter can contain
     // arithmetic, logical, comparison and ternary operators.
     //
-    // FIXME: This also accepts sequences of operators that are not in the scope
-    // of a template argument list.
+    // FIXME: This also accepts sequences of operators that are not in the
+    // scope of a template argument list.
     //
     // In a C++ lambda a template type can only occur after an arrow. We use
     // this as an heuristic to distinguish between Objective-C expressions
@@ -2286,8 +2322,9 @@
     // Parse a type definition.
     nextToken();
 
-    // Eat the type declaration. For braced inline object types, balance braces,
-    // otherwise just parse until finding an l_brace for the function body.
+    // Eat the type declaration. For braced inline object types, balance
+    // braces, otherwise just parse until finding an l_brace for the function
+    // body.
     if (FormatTok->is(tok::l_brace))
       tryToParseBracedList();
     else
@@ -2391,10 +2428,10 @@
       }
       break;
     case tok::semi:
-      // JavaScript (or more precisely TypeScript) can have semicolons in braced
-      // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
-      // used for error recovery if we have otherwise determined that this is
-      // a braced list.
+      // JavaScript (or more precisely TypeScript) can have semicolons in
+      // braced lists (in so-called TypeMemberLists). Thus, the semicolon
+      // cannot be used for error recovery if we have otherwise determined
+      // that this is a braced list.
       if (Style.isJavaScript()) {
         nextToken();
         break;
@@ -2932,8 +2969,8 @@
                /*KeepBraces=*/true, /*IfKind=*/nullptr,
                ManageWhitesmithsBraces);
 
-    // Munch the semicolon after a namespace. This is more common than one would
-    // think. Putting the semicolon into its own line is very ugly.
+    // Munch the semicolon after a namespace. This is more common than one
+    // would think. Putting the semicolon into its own line is very ugly.
     if (FormatTok->is(tok::semi))
       nextToken();
 
@@ -2979,7 +3016,8 @@
     if (FormatTok->is(tok::l_paren)) {
       parseParens();
 
-      // If there is a class body of an anonymous class, consume that as child.
+      // If there is a class body of an anonymous class, consume that as
+      // child.
       if (FormatTok->is(tok::l_brace))
         parseChildBlock();
       return;
@@ -3033,8 +3071,8 @@
     nextToken();
   if (HasParens && FormatTok->is(tok::l_paren)) {
     // The type is only set for Verilog basically because we were afraid to
-    // change the existing behavior for loops. See the discussion on D121756 for
-    // details.
+    // change the existing behavior for loops. See the discussion on D121756
+    // for details.
     if (Style.isVerilog())
       FormatTok->setFinalizedType(TT_ConditionLParen);
     parseParens();
@@ -3228,7 +3266,8 @@
     parseRequiresExpression(RequiresToken);
     return false;
   case tok::l_paren:
-    // Clauses and expression can start with a paren, it's unclear what we have.
+    // Clauses and expression can start with a paren, it's unclear what we
+    // have.
     break;
   default:
     // All other tokens can only be a clause.
@@ -3290,8 +3329,8 @@
   // Now we look forward and try to check if the paren content is a parameter
   // list. The parameters can be cv-qualified and contain references or
   // pointers.
-  // So we want basically to check for TYPE NAME, but TYPE can contain all kinds
-  // of stuff: typename, const, *, &, &&, ::, identifiers.
+  // So we want basically to check for TYPE NAME, but TYPE can contain all
+  // kinds of stuff: typename, const, *, &, &&, ::, identifiers.
 
   unsigned StoredPosition = Tokens->getPosition();
   FormatToken *NextToken = Tokens->getNextToken();
@@ -3367,8 +3406,8 @@
   assert(RequiresToken->is(tok::kw_requires) && "'requires' expected");
 
   // If there is no previous token, we are within a requires expression,
-  // otherwise we will always have the template or function declaration in front
-  // of it.
+  // otherwise we will always have the template or function declaration in
+  // front of it.
   bool InRequiresExpression =
       !RequiresToken->Previous ||
       RequiresToken->Previous->is(TT_RequiresExpressionLBrace);
@@ -3415,21 +3454,21 @@
 /// This is the body of a requires clause. It returns, when the parsing is
 /// complete, or the expression is incorrect.
 void UnwrappedLineParser::parseConstraintExpression() {
-  // The special handling for lambdas is needed since tryToParseLambda() eats a
-  // token and if a requires expression is the last part of a requires clause
-  // and followed by an attribute like [[nodiscard]] the ClosesRequiresClause is
-  // not set on the correct token. Thus we need to be aware if we even expect a
-  // lambda to be possible.
-  // template <typename T> requires requires { ... } [[nodiscard]] ...;
+  // The special handling for lambdas is needed since tryToParseLambda() eats
+  // a token and if a requires expression is the last part of a requires
+  // clause and followed by an attribute like [[nodiscard]] the
+  // ClosesRequiresClause is not set on the correct token. Thus we need to be
+  // aware if we even expect a lambda to be possible. template <typename T>
+  // requires requires { ... } [[nodiscard]] ...;
   bool LambdaNextTimeAllowed = true;
 
-  // Within lambda declarations, it is permitted to put a requires clause after
-  // its template parameter list, which would place the requires clause right
-  // before the parentheses of the parameters of the lambda declaration. Thus,
-  // we track if we expect to see grouping parentheses at all.
-  // Without this check, `requires foo<T> (T t)` in the below example would be
-  // seen as the whole requires clause, accidentally eating the parameters of
-  // the lambda.
+  // Within lambda declarations, it is permitted to put a requires clause
+  // after its template parameter list, which would place the requires clause
+  // right before the parentheses of the parameters of the lambda declaration.
+  // Thus, we track if we expect to see grouping parentheses at all. Without
+  // this check, `requires foo<T> (T t)` in the below example would be seen as
+  // the whole requires clause, accidentally eating the parameters of the
+  // lambda.
   // [&]<typename T> requires foo<T> (T t) { ... };
   bool TopLevelParensAllowed = true;
 
@@ -3567,9 +3606,9 @@
   if (FormatTok->is(tok::kw_enum))
     nextToken();
 
-  // In TypeScript, "enum" can also be used as property name, e.g. in interface
-  // declarations. An "enum" keyword followed by a colon would be a syntax
-  // error and thus assume it is just an identifier.
+  // In TypeScript, "enum" can also be used as property name, e.g. in
+  // interface declarations. An "enum" keyword followed by a colon would be a
+  // syntax error and thus assume it is just an identifier.
   if (Style.isJavaScript() && FormatTok->isOneOf(tok::colon, tok::question))
     return false;
 
@@ -3833,8 +3872,8 @@
         FormatToken *Previous = FormatTok->Previous;
         if (!Previous ||
             !(Previous->is(tok::r_paren) || Previous->isTypeOrIdentifier())) {
-          // Don't try parsing a lambda if we had a closing parenthesis before,
-          // it was probably a pointer to an array: int (*)[].
+          // Don't try parsing a lambda if we had a closing parenthesis
+          // before, it was probably a pointer to an array: int (*)[].
           if (!tryToParseLambda())
             continue;
         } else {
@@ -4047,9 +4086,9 @@
   if (FormatTok->is(tok::kw_default))
     nextToken();
 
-  // Consume "async function", "function" and "default function", so that these
-  // get parsed as free-standing JS functions, i.e. do not require a trailing
-  // semicolon.
+  // Consume "async function", "function" and "default function", so that
+  // these get parsed as free-standing JS functions, i.e. do not require a
+  // trailing semicolon.
   if (FormatTok->is(Keywords.kw_async))
     nextToken();
   if (FormatTok->is(Keywords.kw_function)) {
@@ -4246,11 +4285,11 @@
 }
 
 void UnwrappedLineParser::parseVerilogCaseLabel() {
-  // The label will get unindented in AnnotatingParser. If there are no leading
-  // spaces, indent the rest here so that things inside the block will be
-  // indented relative to things outside. We don't use parseLabel because we
-  // don't know whether this colon is a label or a ternary expression at this
-  // point.
+  // The label will get unindented in AnnotatingParser. If there are no
+  // leading spaces, indent the rest here so that things inside the block will
+  // be indented relative to things outside. We don't use parseLabel because
+  // we don't know whether this colon is a label or a ternary expression at
+  // this point.
   auto OrigLevel = Line->Level;
   auto FirstLine = CurrentLines->size();
   if (Line->Level == 0 || (Line->InPPDirective && Line->Level <= 1))
@@ -4295,8 +4334,8 @@
       Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths;
 
   // If the current line was expanded from a macro call, we use it to
-  // reconstruct an unwrapped line from the structure of the expanded unwrapped
-  // line and the unexpanded token stream.
+  // reconstruct an unwrapped line from the structure of the expanded
+  // unwrapped line and the unexpanded token stream.
   if (!parsingPPDirective() && !InExpansion && containsExpansion(*Line)) {
     if (!Reconstruct)
       Reconstruct.emplace(Line->Level, Unexpanded);
@@ -4372,10 +4411,10 @@
   // section if its original column is greater or equal to the original start
   // column of the line.
   //
-  // Define the min column token of a line as follows: if a line ends in '{' or
-  // contains a '{' followed by a line comment, then the min column token is
-  // that '{'. Otherwise, the min column token of the line is the first token of
-  // the line.
+  // Define the min column token of a line as follows: if a line ends in '{'
+  // or contains a '{' followed by a line comment, then the min column token
+  // is that '{'. Otherwise, the min column token of the line is the first
+  // token of the line.
   //
   // If Line starts with a token other than a line comment, then FormatTok
   // continues the comment section if its original column is greater than the
@@ -4461,14 +4500,14 @@
 void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
   bool JustComments = Line->Tokens.empty();
   for (FormatToken *Tok : CommentsBeforeNextToken) {
-    // Line comments that belong to the same line comment section are put on the
-    // same line since later we might want to reflow content between them.
+    // Line comments that belong to the same line comment section are put on
+    // the same line since later we might want to reflow content between them.
     // Additional fine-grained breaking of line comment sections is controlled
-    // by the class BreakableLineCommentSection in case it is desirable to keep
-    // several line comment sections in the same unwrapped line.
+    // by the class BreakableLineCommentSection in case it is desirable to
+    // keep several line comment sections in the same unwrapped line.
     //
-    // FIXME: Consider putting separate line comment sections as children to the
-    // unwrapped line instead.
+    // FIXME: Consider putting separate line comment sections as children to
+    // the unwrapped line instead.
     Tok->ContinuesLineCommentSection =
         continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex);
     if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection)
@@ -4509,10 +4548,10 @@
   // Whether or not a line comment token continues a line is controlled by
   // the method continuesLineCommentSection, with the following caveat:
   //
-  // Define a trail of Comments to be a nonempty proper postfix of Comments such
-  // that each comment line from the trail is aligned with the next token, if
-  // the next token exists. If a trail exists, the beginning of the maximal
-  // trail is marked as a start of a new comment section.
+  // Define a trail of Comments to be a nonempty proper postfix of Comments
+  // such that each comment line from the trail is aligned with the next
+  // token, if the next token exists. If a trail exists, the beginning of the
+  // maximal trail is marked as a start of a new comment section.
   //
   // For example in this code:
   //
@@ -4521,8 +4560,8 @@
   //   // line 2 about b
   //   int b;
   //
-  // the two lines about b form a maximal trail, so there are two sections, the
-  // first one consisting of the single comment "// line about a" and the
+  // the two lines about b form a maximal trail, so there are two sections,
+  // the first one consisting of the single comment "// line about a" and the
   // second one consisting of the next two comments.
   if (Comments.empty())
     return;
@@ -4611,7 +4650,8 @@
       Line->Level += LevelDifference;
       // Comments stored before the preprocessor directive need to be output
       // before the preprocessor directive, at the same level as the
-      // preprocessor directive, as we consider them to apply to the directive.
+      // preprocessor directive, as we consider them to apply to the
+      // directive.
       if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
           PPBranchLevel > 0) {
         Line->Level += PPBranchLevel;
@@ -4635,8 +4675,8 @@
       FormatToken *ID = FormatTok;
       unsigned Position = Tokens->getPosition();
 
-      // To correctly parse the code, we need to replace the tokens of the macro
-      // call with its expansion.
+      // To correctly parse the code, we need to replace the tokens of the
+      // macro call with its expansion.
       auto PreCall = std::move(Line);
       Line.reset(new UnwrappedLine);
       bool OldInExpansion = InExpansion;
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -18,6 +18,7 @@
 #include "clang/Basic/TokenKinds.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Support/Debug.h"
+#include <sal.h>
 
 #define DEBUG_TYPE "format-token-annotator"
 
@@ -5011,6 +5012,25 @@
       return true;
     }
 
+    // Handle `string Foo {{set {} get {}}`.
+    if (Style.isCSharp() && Style.BraceWrapping.AfterCSharpProperty &&
+        (Line.First && Line.First->isOneOf(Keywords.kw_get, Keywords.kw_set,
+                                           Keywords.kw_init))) {
+      return true;
+    }
+
+    // string Foo
+    // {
+    //     set; interal get {};
+    // }
+    if (Style.isCSharp() && Style.BraceWrapping.AfterCSharpProperty &&
+        ((Left.isOneOf(Keywords.kw_set, Keywords.kw_get, Keywords.kw_init) &&
+          Right.is(tok::l_brace) && Left.Previous &&
+          Left.Previous->isOneOf(tok::kw_public, tok::kw_private,
+                                 tok::kw_protected, Keywords.kw_internal)))) {
+      return true;
+    }
+
     // Don't attempt to interpret struct return types as structs.
     if (Right.isNot(TT_FunctionLBrace)) {
       return (Line.startsWith(tok::kw_class) &&
@@ -5020,6 +5040,90 @@
     }
   }
 
+  // Handle default `string Foo {set;get }`.
+  if (Style.isCSharp() && Style.AlwaysBreakBetweenShortCSharpProperties &&
+      Left.is(tok::semi) &&
+      Right.isOneOf(Keywords.kw_set, Keywords.kw_get, Keywords.kw_init)) {
+    return true;
+  }
+
+  // Handle non short property on a single line
+  // string Foo {
+  //     set;get;
+  // }
+  if (Style.isCSharp() && !Style.BraceWrapping.AfterFunction &&
+      !Style.AllowShortCSharpPropertiesOnASingleLine) {
+    if (Left.is(tok::l_brace) &&
+        Right.isOneOf(Keywords.kw_set, Keywords.kw_get, Keywords.kw_init)) {
+      return true;
+    }
+    // string Foo {
+    //     <access> set;get;
+    // }
+    if (Left.is(tok::l_brace) &&
+        Right.isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
+                      Keywords.kw_internal) &&
+        Right.Next &&
+        Right.Next->isOneOf(Keywords.kw_set, Keywords.kw_get,
+                            Keywords.kw_init)) {
+      return true;
+    }
+    if (Left.is(tok::semi) && Right.is(tok::r_brace) && Left.Previous &&
+        Left.Previous->isOneOf(Keywords.kw_set, Keywords.kw_get,
+                               Keywords.kw_init)) {
+      return true;
+    }
+  }
+
+  if (Style.isCSharp() && Style.BraceWrapping.AfterFunction &&
+      !Style.AllowShortCSharpPropertiesOnASingleLine) {
+    // string Foo
+    // {
+    //     <access> set;get;
+    // }
+    if (Left.is(tok::l_brace) &&
+        Right.isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
+                      Keywords.kw_internal) &&
+        Right.Next &&
+        Right.Next->isOneOf(Keywords.kw_set, Keywords.kw_get,
+                            Keywords.kw_init)) {
+      return true;
+    }
+    // string Foo
+    // {
+    //     set; <access> get;
+    // }
+    if (Left.is(tok::semi) &&
+        Right.isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
+                      Keywords.kw_internal) &&
+        Right.Next &&
+        Right.Next->isOneOf(Keywords.kw_set, Keywords.kw_get,
+                            Keywords.kw_init)) {
+      return Style.AlwaysBreakBetweenShortCSharpProperties;
+      ;
+    }
+  }
+
+  // string Foo
+  // {
+  //     set; get;
+  // }
+  if (Style.isCSharp() && Style.BraceWrapping.AfterCSharpProperty &&
+      ((Left.is(tok::l_brace) &&
+        Right.isOneOf(Keywords.kw_set, Keywords.kw_get, Keywords.kw_init)))) {
+    return true;
+  }
+
+  // string Foo
+  // {
+  //     set;
+  //     get;
+  // }
+  if (Style.isCSharp() && Style.BraceWrapping.AfterCSharpProperty &&
+      (Left.is(tok::semi) && Right.is(tok::r_brace))) {
+    return true;
+  }
+
   if (Left.is(TT_ObjCBlockLBrace) &&
       Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) {
     return true;
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -178,6 +178,7 @@
     IO.mapOptional("AfterCaseLabel", Wrapping.AfterCaseLabel);
     IO.mapOptional("AfterClass", Wrapping.AfterClass);
     IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
+    IO.mapOptional("AfterCSharpProperty", Wrapping.AfterCSharpProperty);
     IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
     IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
     IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
@@ -857,6 +858,8 @@
                    Style.AllowShortBlocksOnASingleLine);
     IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
                    Style.AllowShortCaseLabelsOnASingleLine);
+    IO.mapOptional("AllowShortCSharpPropertiesOnASingleLine",
+                   Style.AllowShortCSharpPropertiesOnASingleLine);
     IO.mapOptional("AllowShortEnumsOnASingleLine",
                    Style.AllowShortEnumsOnASingleLine);
     IO.mapOptional("AllowShortFunctionsOnASingleLine",
@@ -873,6 +876,8 @@
                    Style.AlwaysBreakAfterReturnType);
     IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
                    Style.AlwaysBreakBeforeMultilineStrings);
+    IO.mapOptional("AlwaysBreakBetweenShortCSharpProperties",
+                   Style.AlwaysBreakBetweenShortCSharpProperties);
     IO.mapOptional("AlwaysBreakTemplateDeclarations",
                    Style.AlwaysBreakTemplateDeclarations);
     IO.mapOptional("AttributeMacros", Style.AttributeMacros);
@@ -1174,6 +1179,7 @@
   Expanded.BraceWrapping = {/*AfterCaseLabel=*/false,
                             /*AfterClass=*/false,
                             /*AfterControlStatement=*/FormatStyle::BWACS_Never,
+                            /*AfterCSharpProperty=*/false,
                             /*AfterEnum=*/false,
                             /*AfterFunction=*/false,
                             /*AfterNamespace=*/false,
@@ -1247,6 +1253,7 @@
         /*AfterCaseLabel=*/true,
         /*AfterClass=*/true,
         /*AfterControlStatement=*/FormatStyle::BWACS_Always,
+        /*AfterCSharpProperty=*/false,
         /*AfterEnum=*/true,
         /*AfterFunction=*/true,
         /*AfterNamespace=*/true,
@@ -1324,6 +1331,7 @@
   LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
   LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
   LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
+  LLVMStyle.AllowShortCSharpPropertiesOnASingleLine = true;
   LLVMStyle.AllowShortEnumsOnASingleLine = true;
   LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
   LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
@@ -1332,29 +1340,33 @@
   LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
   LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
   LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
+  LLVMStyle.AlwaysBreakBetweenShortCSharpProperties = false;
   LLVMStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_MultiLine;
   LLVMStyle.AttributeMacros.push_back("__capability");
   LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both;
   LLVMStyle.BinPackArguments = true;
   LLVMStyle.BinPackParameters = true;
-  LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false,
-                             /*AfterClass=*/false,
-                             /*AfterControlStatement=*/FormatStyle::BWACS_Never,
-                             /*AfterEnum=*/false,
-                             /*AfterFunction=*/false,
-                             /*AfterNamespace=*/false,
-                             /*AfterObjCDeclaration=*/false,
-                             /*AfterStruct=*/false,
-                             /*AfterUnion=*/false,
-                             /*AfterExternBlock=*/false,
-                             /*BeforeCatch=*/false,
-                             /*BeforeElse=*/false,
-                             /*BeforeLambdaBody=*/false,
-                             /*BeforeWhile=*/false,
-                             /*IndentBraces=*/false,
-                             /*SplitEmptyFunction=*/true,
-                             /*SplitEmptyRecord=*/true,
-                             /*SplitEmptyNamespace=*/true};
+  LLVMStyle.BraceWrapping = {
+      /*AfterCaseLabel=*/false,
+      /*AfterClass=*/false,
+      /*AfterControlStatement=*/FormatStyle::BWACS_Never,
+      /*AfterCSharpProperty=*/false,
+      /*AfterEnum=*/false,
+      /*AfterFunction=*/false,
+      /*AfterNamespace=*/false,
+      /*AfterObjCDeclaration=*/false,
+      /*AfterStruct=*/false,
+      /*AfterUnion=*/false,
+      /*AfterExternBlock=*/false,
+      /*BeforeCatch=*/false,
+      /*BeforeElse=*/false,
+      /*BeforeLambdaBody=*/false,
+      /*BeforeWhile=*/false,
+      /*IndentBraces=*/false,
+      /*SplitEmptyFunction=*/true,
+      /*SplitEmptyRecord=*/true,
+      /*SplitEmptyNamespace=*/true,
+  };
   LLVMStyle.BreakAfterAttributes = FormatStyle::ABS_Never;
   LLVMStyle.BreakAfterJavaFieldAnnotations = false;
   LLVMStyle.BreakArrays = true;
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -538,6 +538,16 @@
   /// \version 3.6
   bool AllowShortCaseLabelsOnASingleLine;
 
+  /// If ``true``, short CSharp properties will be contracted to a single line.
+  /// \code
+  ///   true:                                   false:
+  ///   public string Foo { set; get; }         public string Foo {
+  ///                                             set; get;
+  ///                                           }
+  /// \endcode
+  /// \version 17.0
+  bool AllowShortCSharpPropertiesOnASingleLine;
+
   /// Allow short enums on a single line.
   /// \code
   ///   true:
@@ -858,6 +868,17 @@
     BTDS_Yes
   };
 
+  /// If ``true``, short CSharp properties will be contracted to a single line.
+  /// \code
+  ///   true:                                   false:
+  ///   public string Foo {                     public string Foo {
+  ///     set;                                    set; get;
+  ///     get;                                  }
+  ///   }
+  /// \endcode
+  /// \version 17.0
+  bool AlwaysBreakBetweenShortCSharpProperties;
+
   /// The template declaration breaking style to use.
   /// \version 3.4
   BreakTemplateDeclarationsStyle AlwaysBreakTemplateDeclarations;
@@ -1002,6 +1023,7 @@
     ///                                         }
     /// \endcode
     bool AfterCaseLabel;
+
     /// Wrap class definitions.
     /// \code
     ///   true:
@@ -1015,6 +1037,33 @@
 
     /// Wrap control statements (``if``/``for``/``while``/``switch``/..).
     BraceWrappingAfterControlStatementStyle AfterControlStatement;
+
+    /// Wrap C# setter/getter properties.
+    /// \code
+    ///   true:
+    ///   string Foo {
+    ///     get
+    ///     {
+    ///       return _foo;
+    ///     }
+    ///     set
+    ///     {
+    ///       _foo = value;
+    ///     }
+    ///   }
+    ///
+    ///   false:
+    ///   string Foo {
+    ///     get {
+    ///       return _foo;
+    ///     }
+    ///     set {
+    ///       return _value
+    ///     }
+    ///   }
+    /// \endcode
+    bool AfterCSharpProperty;
+
     /// Wrap enum definitions.
     /// \code
     ///   true:
@@ -1205,6 +1254,28 @@
     /// \endcode
     ///
     bool SplitEmptyNamespace;
+
+    bool operator==(const BraceWrappingFlags &Other) const {
+      return AfterCaseLabel == Other.AfterCaseLabel &&
+             AfterClass == Other.AfterClass &&
+             AfterControlStatement == Other.AfterControlStatement &&
+             AfterCSharpProperty == Other.AfterCSharpProperty &&
+             AfterEnum == Other.AfterEnum &&
+             AfterFunction == Other.AfterFunction &&
+             AfterNamespace == Other.AfterNamespace &&
+             AfterObjCDeclaration == Other.AfterObjCDeclaration &&
+             AfterStruct == Other.AfterStruct &&
+             AfterUnion == Other.AfterUnion &&
+             AfterExternBlock == Other.AfterExternBlock &&
+             BeforeCatch == Other.BeforeCatch &&
+             BeforeElse == Other.BeforeElse &&
+             BeforeLambdaBody == Other.BeforeLambdaBody &&
+             BeforeWhile == Other.BeforeWhile &&
+             IndentBraces == Other.IndentBraces &&
+             SplitEmptyFunction == Other.SplitEmptyFunction &&
+             SplitEmptyRecord == Other.SplitEmptyRecord &&
+             SplitEmptyNamespace == Other.SplitEmptyNamespace;
+    }
   };
 
   /// Control of individual brace wrapping cases.
@@ -4270,6 +4341,8 @@
            AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
            AllowShortCaseLabelsOnASingleLine ==
                R.AllowShortCaseLabelsOnASingleLine &&
+           AllowShortCSharpPropertiesOnASingleLine ==
+               R.AllowShortCSharpPropertiesOnASingleLine &&
            AllowShortEnumsOnASingleLine == R.AllowShortEnumsOnASingleLine &&
            AllowShortFunctionsOnASingleLine ==
                R.AllowShortFunctionsOnASingleLine &&
@@ -4280,6 +4353,8 @@
            AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType &&
            AlwaysBreakBeforeMultilineStrings ==
                R.AlwaysBreakBeforeMultilineStrings &&
+           AlwaysBreakBetweenShortCSharpProperties ==
+               R.AlwaysBreakBetweenShortCSharpProperties &&
            AlwaysBreakTemplateDeclarations ==
                R.AlwaysBreakTemplateDeclarations &&
            AttributeMacros == R.AttributeMacros &&
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -468,6 +468,12 @@
 - Add additional Qualifier Ordering support for special cases such
   as templates, requires clauses, long qualified names.
 - Fix all known issues associated with ``LambdaBodyIndentation: OuterScope``.
+- Add ``AfterCSharpProperty`` style to option ``BraceWrapping`` to allow
+  newline before the opening brace of ``set;get;``.
+- Add ``AllowShortCSharpPropertiesOnASingleLine`` style to allow C# properties
+  To be on a single line.
+- Add ``AlwaysBreakBetweenShortCSharpProperties`` style to allow C# auto 
+  properties to be split across multiple lines.
 
 libclang
 --------
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -1042,6 +1042,18 @@
 
 
 
+.. _AllowShortCSharpPropertiesOnASingleLine:
+
+**AllowShortCSharpPropertiesOnASingleLine** (``Boolean``) :versionbadge:`clang-format 17.0` :ref:`¶ <AllowShortCSharpPropertiesOnASingleLine>`
+  If ``true``, short CSharp properties will be contracted to a single line.
+
+  .. code-block:: c++
+
+    true:                                   false:
+    public string Foo { set; get; }         public string Foo {
+                                              set; get;
+                                            }
+
 .. _AllowShortCaseLabelsOnASingleLine:
 
 **AllowShortCaseLabelsOnASingleLine** (``Boolean``) :versionbadge:`clang-format 3.6` :ref:`¶ <AllowShortCaseLabelsOnASingleLine>`
@@ -1385,6 +1397,19 @@
          "bbbb"                                    "cccc";
          "cccc";
 
+.. _AlwaysBreakBetweenShortCSharpProperties:
+
+**AlwaysBreakBetweenShortCSharpProperties** (``Boolean``) :versionbadge:`clang-format 17.0` :ref:`¶ <AlwaysBreakBetweenShortCSharpProperties>`
+  If ``true``, short CSharp properties will be contracted to a single line.
+
+  .. code-block:: c++
+
+    true:                                   false:
+    public string Foo {                     public string Foo {
+      set;                                    set; get;
+      get;                                  }
+    }
+
 .. _AlwaysBreakTemplateDeclarations:
 
 **AlwaysBreakTemplateDeclarations** (``BreakTemplateDeclarationsStyle``) :versionbadge:`clang-format 3.4` :ref:`¶ <AlwaysBreakTemplateDeclarations>`
@@ -1628,6 +1653,32 @@
         {}
 
 
+  * ``bool AfterCSharpProperty`` Wrap C# setter/getter properties.
+
+    .. code-block:: c++
+
+      true:
+      string Foo {
+        get
+        {
+          return _foo;
+        }
+        set
+        {
+          _foo = value;
+        }
+      }
+
+      false:
+      string Foo {
+        get {
+          return _foo;
+        }
+        set {
+          return _value
+        }
+      }
+
   * ``bool AfterEnum`` Wrap enum definitions.
 
     .. code-block:: c++
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to