jbcoe updated this revision to Diff 246235.
jbcoe added a comment.
This revision is now accepted and ready to land.

Simplify logic for merging property accessors


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

https://reviews.llvm.org/D75006

Files:
  clang/lib/Format/UnwrappedLineFormatter.cpp
  clang/unittests/Format/FormatTestCSharp.cpp

Index: clang/unittests/Format/FormatTestCSharp.cpp
===================================================================
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -240,18 +240,12 @@
 
   verifyFormat("[TestMethod]\n"
                "public string Host\n"
-               "{\n"
-               "    set;\n"
-               "    get;\n"
-               "}");
+               "{ set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
                "listening on provided host\")]\n"
                "public string Host\n"
-               "{\n"
-               "    set;\n"
-               "    get;\n"
-               "}");
+               "{ set; get; }");
 
   verifyFormat(
       "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
@@ -554,5 +548,32 @@
                Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat("int Value { get }", Style);
+  verifyFormat("int Value { get; }", Style);
+  verifyFormat("int Value { internal get; }", Style);
+  verifyFormat("int Value { get; } = 0", Style);
+  verifyFormat("int Value { set }", Style);
+  verifyFormat("int Value { set; }", Style);
+  verifyFormat("int Value { internal set; }", Style);
+  verifyFormat("int Value { set; } = 0", Style);
+  verifyFormat("int Value { get; set }", Style);
+  verifyFormat("int Value { set; get }", Style);
+  verifyFormat("int Value { get; private set; }", Style);
+  verifyFormat("int Value { get; set; }", Style);
+  verifyFormat("int Value { get; set; } = 0", Style);
+  verifyFormat("int Value { internal get; internal set; }", Style);
+
+  // Do not wrap expression body definitions.
+  verifyFormat(R"(//
+public string Name {
+  get => _name;
+  set => _name = value;
+})",
+               Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===================================================================
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -292,6 +292,13 @@
       }
     }
 
+    // Try to merge a CSharp property declaration like `{ get; private set }`.
+    if (Style.isCSharp()) {
+      unsigned CSPA = tryMergeCSharpPropertyAccessor(I, E, Limit);
+      if (CSPA > 0)
+        return CSPA;
+    }
+
     // Try to merge a function block with left brace unwrapped
     if (TheLine->Last->is(TT_FunctionLBrace) &&
         TheLine->First != TheLine->Last) {
@@ -421,6 +428,64 @@
     return 0;
   }
 
+  // true for lines of the form [access-modifier] {get,set} [;]
+  bool isMergeablePropertyAccessor(const AnnotatedLine *Line) {
+    auto *Tok = Line->First;
+    if (!Tok)
+      return false;
+
+    if (Tok->isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private,
+                     Keywords.kw_internal))
+      Tok = Tok->Next;
+
+    if (!Tok || (Tok->TokenText != "get" && Tok->TokenText != "set"))
+      return false;
+
+    if (!Tok->Next || Tok->Next->is(tok::semi))
+      return true;
+
+    return false;
+  }
+
+  unsigned tryMergeCSharpPropertyAccessor(
+      SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+      SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned /*Limit*/) {
+
+    auto CurrentLine = I;
+    // Does line start with `{`
+    if (!(*CurrentLine)->Last || (*CurrentLine)->Last->isNot(TT_FunctionLBrace))
+      return 0;
+    ++CurrentLine;
+
+    unsigned MergedLines = 0;
+    bool HasGetOrSet = false;
+    while (CurrentLine != E) {
+      bool LineIsGetOrSet = isMergeablePropertyAccessor(*CurrentLine);
+      HasGetOrSet = HasGetOrSet || LineIsGetOrSet;
+      if (LineIsGetOrSet) {
+        ++CurrentLine;
+        ++MergedLines;
+        continue;
+      }
+      auto *Tok = (*CurrentLine)->First;
+      if (Tok && Tok->is(tok::r_brace)) {
+        ++CurrentLine;
+        ++MergedLines;
+        // See if the next line is a default value so that we can merge `{ get;
+        // set } = 0`
+        if (CurrentLine != E && (*CurrentLine)->First &&
+            (*CurrentLine)->First->is(tok::equal)) {
+          ++MergedLines;
+        }
+        break;
+      }
+      // Not a '}' or a get/set line so do not merege lines.
+      return 0;
+    }
+
+    return HasGetOrSet ? MergedLines : 0;
+  }
+
   unsigned
   tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
                             SmallVectorImpl<AnnotatedLine *>::const_iterator E,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to