[PATCH] D115738: [clang-format] Code following C# Lambda Expressions has wrong formatting

2021-12-14 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added inline comments.



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:2007
+if (FormatTok->is(tok::l_brace)) {
+  if (Style.isCSharp() && Style.BraceWrapping.AfterFunction == true) {
+FormatTok->MustBreakBefore = true;

I think this check for `Style.isCSharp()` is redundant as it's already checked 
above.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D115738

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


[PATCH] D104388: [clang-format] PR50727 C# Invoke Lamda Expression indentation incorrect

2021-06-29 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe accepted this revision.
jbcoe added a subscriber: krasimir.
jbcoe added a comment.

Some outstanding nits to address but this looks good to me.

With @krasimir I implemented a good fraction of the C# support and am confident 
that these changes are an improvement.


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

https://reviews.llvm.org/D104388

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


[PATCH] D103307: [clang-format] successive C# attributes cause line breaking issues

2021-05-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe accepted this revision.
jbcoe added a comment.
This revision is now accepted and ready to land.

Thanks for this!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103307

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


[PATCH] D101702: [clang-format] Add more support for C# 8 nullables

2021-05-05 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

Thanks for this patch!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D101702

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


[PATCH] D82016: [clang-format] [PR462254] fix indentation of default and break correctly in whitesmiths style

2020-06-17 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe accepted this revision.
jbcoe added a comment.
This revision is now accepted and ready to land.

Thanks for this!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82016



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


[PATCH] D81467: [clang-format] Microsoft style fixes for C# properties

2020-06-09 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added reviewers: krasimir, MyDeveloperDay.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
krasimir accepted this revision.
krasimir added a comment.
This revision is now accepted and ready to land.

Thank you!


There should be no line break before the opening brace for Microsoft style 
property accessors when the accessor is a simple `{ get; set }`.

https://docs.microsoft.com/en-us/dotnet/csharp/properties


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81467

Files:
  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
@@ -245,13 +245,11 @@
"}");
 
   verifyFormat("[TestMethod]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
"listening on provided host\")]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat(
   "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
@@ -710,13 +708,6 @@
   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.AfterFunction = true;
 
-  verifyFormat(R"(//
-public class SaleItem {
-  public decimal Price
-  { get; set; }
-})",
-   Style);
-
   verifyFormat(R"(//
 class TimePeriod {
   public double Hours
@@ -730,6 +721,17 @@
   }
 })",
Style);
+ 
+  // Microsoft style trivial property accessors have no line break before the
+  // opening brace.
+  auto MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
+  verifyFormat(R"(//
+public class SaleItem
+{
+public decimal Price { get; set; }
+})",
+   MicrosoftStyle);
+
 }
 
 TEST_F(FormatTestCSharp, CSharpSpaces) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1542,7 +1542,7 @@
   // Try to parse the property accessor:
   // 
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
   Tokens->setPosition(StoredPosition);
-  if (Style.BraceWrapping.AfterFunction == true)
+  if (!IsTrivialPropertyAccessor && Style.BraceWrapping.AfterFunction == true)
 addUnwrappedLine();
   nextToken();
   do {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -245,13 +245,11 @@
"}");
 
   verifyFormat("[TestMethod]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
"listening on provided host\")]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat(
   "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
@@ -710,13 +708,6 @@
   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
   Style.BraceWrapping.AfterFunction = true;
 
-  verifyFormat(R"(//
-public class SaleItem {
-  public decimal Price
-  { get; set; }
-})",
-   Style);
-
   verifyFormat(R"(//
 class TimePeriod {
   public double Hours
@@ -730,6 +721,17 @@
   }
 })",
Style);
+ 
+  // Microsoft style trivial property accessors have no line break before the
+  // opening brace.
+  auto MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
+  verifyFormat(R"(//
+public class SaleItem
+{
+public decimal Price { get; set; }
+})",
+   MicrosoftStyle);
+
 }
 
 TEST_F(FormatTestCSharp, CSharpSpaces) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1542,7 +1542,7 @@
   // Try to parse the property accessor:
   // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
   Tokens->setPosition(StoredPosition);
-  if (Style.BraceWrapping.AfterFunction == true)
+  if (!IsTrivialPropertyAccessor && Style.BraceWrapping.AfterFunction == true)
 addUnwrappedLine();
   nextToken();
   do {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81394: [clang-format] Brace breaking for C# lambdas

2020-06-08 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 269262.
jbcoe added a comment.

Amend comment - behaviour with addUnwrappedLine is expected and applied fix is 
fine.


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

https://reviews.llvm.org/D81394

Files:
  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
@@ -525,6 +525,33 @@
   EXPECT_EQ(Code, format(Code, Style));
 }
 
+TEST_F(FormatTestCSharp, CSharpLambdas) {
+  FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
+  FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(//
+class MyClass {
+  Action greet = name => {
+string greeting = $"Hello {name}!";
+Console.WriteLine(greeting);
+  };
+})",
+   GoogleStyle);
+
+  // Microsoft Style:
+  // 
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas
+  verifyFormat(R"(//
+class MyClass
+{
+Action greet = name =>
+{
+string greeting = $"Hello {name}!";
+Console.WriteLine(greeting);
+};
+})",
+   MicrosoftStyle);
+}
+
 TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1459,8 +1459,14 @@
   // followed by a curly.
   if (FormatTok->is(TT_JsFatArrow)) {
 nextToken();
-if (FormatTok->is(tok::l_brace))
+if (FormatTok->is(tok::l_brace)) {
+  // C# may break after => if the next character is a newline.
+  if (Style.isCSharp() && Style.BraceWrapping.AfterFunction == true) {
+// calling `addUnwrappedLine()` here causes odd parsing errors.
+FormatTok->MustBreakBefore = true;
+  }
   parseChildBlock();
+}
 break;
   }
 


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -525,6 +525,33 @@
   EXPECT_EQ(Code, format(Code, Style));
 }
 
+TEST_F(FormatTestCSharp, CSharpLambdas) {
+  FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
+  FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(//
+class MyClass {
+  Action greet = name => {
+string greeting = $"Hello {name}!";
+Console.WriteLine(greeting);
+  };
+})",
+   GoogleStyle);
+
+  // Microsoft Style:
+  // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas
+  verifyFormat(R"(//
+class MyClass
+{
+Action greet = name =>
+{
+string greeting = $"Hello {name}!";
+Console.WriteLine(greeting);
+};
+})",
+   MicrosoftStyle);
+}
+
 TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1459,8 +1459,14 @@
   // followed by a curly.
   if (FormatTok->is(TT_JsFatArrow)) {
 nextToken();
-if (FormatTok->is(tok::l_brace))
+if (FormatTok->is(tok::l_brace)) {
+  // C# may break after => if the next character is a newline.
+  if (Style.isCSharp() && Style.BraceWrapping.AfterFunction == true) {
+// calling `addUnwrappedLine()` here causes odd parsing errors.
+FormatTok->MustBreakBefore = true;
+  }
   parseChildBlock();
+}
 break;
   }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81255: [clang-format] treat 'lock' as a keyword for C# code

2020-06-05 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
krasimir accepted this revision.
This revision is now accepted and ready to land.

This will put a space in `lock (process)` when spaces are required after 
keywords.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81255

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -741,6 +741,9 @@
 })",
Style);
 
+  // space after lock in `lock (processes)`.
+  verifyFormat("lock (process)", Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3080,7 +3080,8 @@
 
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
-  if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
+  if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when,
+   Keywords.kw_lock))
 return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements 
||
spaceRequiredBeforeParens(Right);
   } else if (Style.Language == FormatStyle::LK_JavaScript) {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -741,6 +741,9 @@
 })",
Style);
 
+  // space after lock in `lock (processes)`.
+  verifyFormat("lock (process)", Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3080,7 +3080,8 @@
 
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
-  if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
+  if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when,
+   Keywords.kw_lock))
 return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements ||
spaceRequiredBeforeParens(Right);
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D80490: [clang-tidy] Check for rule of five and zero.

2020-06-01 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

Perhaps associated is https://github.com/isocpp/CppCoreGuidelines/issues/870 
which was closed but never (in my mind) resolved.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D80490



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


[PATCH] D80490: [clang-tidy] Check for rule of five and zero.

2020-06-01 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

https://reviews.llvm.org/D16376 was written by me, I'm afraid I don't recall 
why I abandoned it and was surprised to see that it had not been submitted.

I don't feel comfortable approving work based on my own but this patch looks 
great to me.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D80490



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


[PATCH] D79000: [clang-format] C# property formatting can be controlled by config options

2020-05-15 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe closed this revision.
jbcoe added a comment.

Submitted as 8fa743ab82027da443bac050e86b70bcdb78cbee 



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79000



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


[PATCH] D79715: [clang-format] Update GoogleStyle for C# code to match Google's internal C# style guide

2020-05-14 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe planned changes to this revision.
jbcoe added a comment.

I will get the Google Style guide uploaded and update this patch with a link.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79715



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


[PATCH] D79715: [clang-format] Update GoogleStyle for C# code to match Google's internal C# style guide

2020-05-11 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

I expect that accepting this patch will need require an update to be made to 
https://github.com/google/styleguide.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79715



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


[PATCH] D79715: [clang-format] Update GoogleStyle for C# code to match Google's internal C# style guide

2020-05-11 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79715

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -581,8 +581,7 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
   verifyFormat(R"(//
-PrintOrderDetails(orderNum: 31, productName: "Red Mug",
-  sellerName: "Gift Shop");)",
+PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift 
Shop");)",
Style);
 
   // Ensure that trailing comments do not cause problems.
@@ -639,8 +638,7 @@
 get { return _seconds / 3600; }
 set {
   if (value < 0 || value > 24)
-throw new ArgumentOutOfRangeException(
-$"{nameof(value)} must be between 0 and 24.");
+throw new ArgumentOutOfRangeException($"{nameof(value)} must be 
between 0 and 24.");
   _seconds = value * 3600;
 }
   }
@@ -727,7 +725,9 @@
 
   verifyFormat(R"(//
 public class A {
-  void foo() { int? value = some.bar(); }
+  void foo() {
+int? value = some.bar();
+  }
 })",
Style); // int? is nullable not a conditional expression.
 
@@ -772,16 +772,15 @@
 where TKey : IComparable
 where TVal : IMyInterface {
   public void MyMethod(T t)
-  where T : IMyInterface { doThing(); }
+  where T : IMyInterface {
+doThing();
+  }
 })",
Style);
 
   verifyFormat(R"(//
 class ItemFactory
-where T : new(),
-  IAnInterface,
-  IAnotherInterface,
-  IAnotherInterfaceStill {})",
+where T : new(), IAnInterface, IAnotherInterface, 
IAnotherInterfaceStill {})",
Style);
 
   Style.ColumnLimit = 50; // Force lines to be wrapped.
Index: clang/lib/Format/Format.cpp
===
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -14,6 +14,7 @@
 
 #include "clang/Format/Format.h"
 #include "AffectedRangeManager.h"
+#include "BreakableToken.h"
 #include "ContinuationIndenter.h"
 #include "FormatInternal.h"
 #include "FormatTokenLexer.h"
@@ -997,6 +998,12 @@
 // #imports, etc.)
 GoogleStyle.IncludeStyle.IncludeBlocks =
 tooling::IncludeStyle::IBS_Preserve;
+  } else if (Language == FormatStyle::LK_CSharp) {
+GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
+GoogleStyle.BreakStringLiterals = false;
+GoogleStyle.ColumnLimit = 100;
+GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
   }
 
   return GoogleStyle;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -581,8 +581,7 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
   verifyFormat(R"(//
-PrintOrderDetails(orderNum: 31, productName: "Red Mug",
-  sellerName: "Gift Shop");)",
+PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");)",
Style);
 
   // Ensure that trailing comments do not cause problems.
@@ -639,8 +638,7 @@
 get { return _seconds / 3600; }
 set {
   if (value < 0 || value > 24)
-throw new ArgumentOutOfRangeException(
-$"{nameof(value)} must be between 0 and 24.");
+throw new ArgumentOutOfRangeException($"{nameof(value)} must be between 0 and 24.");
   _seconds = value * 3600;
 }
   }
@@ -727,7 +725,9 @@
 
   verifyFormat(R"(//
 public class A {
-  void foo() { int? value = some.bar(); }
+  void foo() {
+int? value = some.bar();
+  }
 })",
Style); // int? is nullable not a conditional expression.
 
@@ -772,16 +772,15 @@
 where TKey : IComparable
 where TVal : IMyInterface {
   public void MyMethod(T t)
-  where T : IMyInterface { doThing(); }
+  where T : IMyInterface {
+doThing();
+  }
 })",
Style);
 
   verifyFormat(R"(//
 class ItemFactory
-where T : new(),
-  IAnInterface,
-  IAnotherInterface,
-  IAnotherInterfaceStill {})",
+where T : new(), IAnInterface, IAnotherInterface, IAnotherInterfaceStill {})",
Style);
 
   Style.ColumnLimit = 50; // Force lines to be wrapped.
Index: clang/lib/Format/Format.cpp
===
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -14,6 +14,7 @@
 
 #include "clang/Format/Format.h"
 #include "Af

[PATCH] D79414: [clang-format] C# always regards && as a binary operator

2020-05-05 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added reviewers: krasimir, MyDeveloperDay.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
MyDeveloperDay accepted this revision.
MyDeveloperDay added a comment.
This revision is now accepted and ready to land.

LGTM, thank you


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79414

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -706,6 +706,9 @@
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
   verifyFormat(R"(var (key, value))", Style);
 
+  // `&&` is not seen as a reference.
+  verifyFormat(R"(A == typeof(X) && someBool)", Style);
+
   // Not seen as a C-style cast.
   verifyFormat(R"(//
 foreach ((A a, B b) in someList) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1852,6 +1852,10 @@
 if (Style.Language == FormatStyle::LK_JavaScript)
   return TT_BinaryOperator;
 
+// && in C# must be a binary operator.
+if (Style.isCSharp() && Tok.is(tok::ampamp))
+  return TT_BinaryOperator;
+
 const FormatToken *PrevToken = Tok.getPreviousNonComment();
 if (!PrevToken)
   return TT_UnaryOperator;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -706,6 +706,9 @@
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
   verifyFormat(R"(var (key, value))", Style);
 
+  // `&&` is not seen as a reference.
+  verifyFormat(R"(A == typeof(X) && someBool)", Style);
+
   // Not seen as a C-style cast.
   verifyFormat(R"(//
 foreach ((A a, B b) in someList) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1852,6 +1852,10 @@
 if (Style.Language == FormatStyle::LK_JavaScript)
   return TT_BinaryOperator;
 
+// && in C# must be a binary operator.
+if (Style.isCSharp() && Tok.is(tok::ampamp))
+  return TT_BinaryOperator;
+
 const FormatToken *PrevToken = Tok.getPreviousNonComment();
 if (!PrevToken)
   return TT_UnaryOperator;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D79000: [clang-format] C# property formatting can be controlled by config options

2020-04-29 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

  public int Style2
  { get; set }

appears in MS examples 
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties

  public int Style2 { get; set }

is the style we use in our code (where the formatter will be put to immediate 
use).

Other options can be added/supported (maybe a CSharpPropertyStyle enum?) but I 
don't think I'm going to have time to devote to that in the immediate future. 
Happy to review/advise as needed.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79000



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


[PATCH] D79000: [clang-format] C# property formatting can be controlled by config options

2020-04-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

Reverted this commit. Will pick this up tomorrow. Apologies for the noise!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79000



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


[PATCH] D79000: [clang-format] C# property formatting can be controlled by config options

2020-04-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

I've just merged this in by mistake.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79000



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


[PATCH] D79008: [clang-format] insert space after C# keyword var in var (key, value)

2020-04-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added reviewers: krasimir, MyDeveloperDay.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79008

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -698,6 +698,7 @@
   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
 
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
+  verifyFormat(R"(var (key, value))", Style);
 
   // Not seen as a C-style cast.
   verifyFormat(R"(//
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3053,6 +3053,10 @@
 if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;
 
+// space after var in `var (key, value)`
+if (Left.is(Keywords.kw_var) && Right.is(tok::l_paren))
+  return true;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -698,6 +698,7 @@
   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
 
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
+  verifyFormat(R"(var (key, value))", Style);
 
   // Not seen as a C-style cast.
   verifyFormat(R"(//
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3053,6 +3053,10 @@
 if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;
 
+// space after var in `var (key, value)`
+if (Left.is(Keywords.kw_var) && Right.is(tok::l_paren))
+  return true;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D79000: [clang-format] C# property accessor formatting can be controlled by config options

2020-04-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added reviewers: krasimir, MyDeveloperDay.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Allow brace wrapping in C# property accessors to be controlled by configuration 
options.

Add new tests and revert old test results for MS style to their old state (as 
intended).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79000

Files:
  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
@@ -245,11 +245,13 @@
"}");
 
   verifyFormat("[TestMethod]\n"
-   "public string Host { set; get; }");
+   "public string Host\n"
+   "{ set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
"listening on provided host\")]\n"
-   "public string Host { set; get; }");
+   "public string Host\n"
+   "{ set; get; }");
 
   verifyFormat(
   "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
@@ -669,6 +671,32 @@
 set => veryLongNamedField = value;
   } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, 
DefaultSecondArgument,
  DefaultThirdArgument);
+})",
+   Style);
+
+  // Brace wrapping and single-lining of accessor can be controlled by config.
+  Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.AfterFunction = true;
+
+  verifyFormat(R"(//
+public class SaleItem {
+  public decimal Price
+  { get; set; }
+})",
+   Style);
+
+  verifyFormat(R"(//
+class TimePeriod {
+  public double Hours
+  {
+get {
+  return _seconds / 3600;
+}
+set {
+  _seconds = value * 3600;
+}
+  }
 })",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1531,6 +1531,8 @@
   // Try to parse the property accessor:
   // 
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
   Tokens->setPosition(StoredPosition);
+  if (Style.BraceWrapping.AfterFunction == true)
+addUnwrappedLine();
   nextToken();
   do {
 switch (FormatTok->Tok.getKind()) {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -245,11 +245,13 @@
"}");
 
   verifyFormat("[TestMethod]\n"
-   "public string Host { set; get; }");
+   "public string Host\n"
+   "{ set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
"listening on provided host\")]\n"
-   "public string Host { set; get; }");
+   "public string Host\n"
+   "{ set; get; }");
 
   verifyFormat(
   "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
@@ -669,6 +671,32 @@
 set => veryLongNamedField = value;
   } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
  DefaultThirdArgument);
+})",
+   Style);
+
+  // Brace wrapping and single-lining of accessor can be controlled by config.
+  Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.AfterFunction = true;
+
+  verifyFormat(R"(//
+public class SaleItem {
+  public decimal Price
+  { get; set; }
+})",
+   Style);
+
+  verifyFormat(R"(//
+class TimePeriod {
+  public double Hours
+  {
+get {
+  return _seconds / 3600;
+}
+set {
+  _seconds = value * 3600;
+}
+  }
 })",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1531,6 +1531,8 @@
   // Try to parse the property accessor:
   // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
   Tokens->setPosition(StoredPosition);
+  if (Style.BraceWrapping.AfterFunction == true)
+addUnwrappedLine();
   nextToken();
   do {
 switch (FormatTok->Tok.getKind()) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D78915: [clang-format] Improved parser for C# properties

2020-04-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 260599.
jbcoe marked 3 inline comments as done.
jbcoe added a comment.

Added missing comments.

Complied with LLVM style.


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

https://reviews.llvm.org/D78915

Files:
  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
@@ -611,6 +611,64 @@
 public string Name {
   get => _name;
   set => _name = value;
+})",
+   Style);
+
+  // Examples taken from
+  // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
+  verifyFormat(R"(
+// Expression body definitions
+public class SaleItem {
+  public decimal Price {
+get => _cost;
+set => _cost = value;
+  }
+})",
+   Style);
+
+  verifyFormat(R"(
+// Properties with backing fields
+class TimePeriod {
+  public double Hours {
+get { return _seconds / 3600; }
+set {
+  if (value < 0 || value > 24)
+throw new ArgumentOutOfRangeException(
+$"{nameof(value)} must be between 0 and 24.");
+  _seconds = value * 3600;
+}
+  }
+})",
+   Style);
+
+  verifyFormat(R"(
+// Auto-implemented properties
+public class SaleItem {
+  public decimal Price { get; set; }
+})",
+   Style);
+
+  // Add column limit to wrap long lines.
+  Style.ColumnLimit = 100;
+
+  // Examples with assignment to default value.
+  verifyFormat(R"(
+// Long assignment to default value
+class MyClass {
+  public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } =
+  VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
+ DefaultThirdArgument);
+})",
+   Style);
+
+  verifyFormat(R"(
+// Long assignment to default value with expression body
+class MyClass {
+  public override VeryLongNamedTypeIndeed VeryLongNamedValue {
+get => veryLongNamedField;
+set => veryLongNamedField = value;
+  } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
+ DefaultThirdArgument);
 })",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -13,6 +13,7 @@
 //===--===//
 
 #include "UnwrappedLineParser.h"
+#include "FormatToken.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -1495,9 +1496,7 @@
   if (FormatTok->Previous->isNot(tok::identifier))
 return false;
 
-  // Try to parse the property accessor braces and contents:
-  // `{ get; set; } = new MyType(defaultValue);`
-  //  ^
+  // See if we are inside a property accessor.
   //
   // Record the current tokenPosition so that we can advance and
   // reset the current token. `Next` is not set yet so we need
@@ -1505,7 +1504,11 @@
   unsigned int StoredPosition = Tokens->getPosition();
   FormatToken *Tok = Tokens->getNextToken();
 
+  // A trivial property accessor is of the form:
+  // { [ACCESS_SPECIFIER] [get]; [ACCESS_SPECIFIER] [set] }
+  // Track these as they do not require line breaks to be introduced.
   bool HasGetOrSet = false;
+  bool IsTrivialPropertyAccessor = true;
   while (!eof()) {
 if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private,
  tok::kw_protected, Keywords.kw_internal, Keywords.kw_get,
@@ -1515,10 +1518,9 @@
   Tok = Tokens->getNextToken();
   continue;
 }
-if (Tok->is(tok::r_brace))
-  break;
-Tokens->setPosition(StoredPosition);
-return false;
+if (Tok->isNot(tok::r_brace))
+  IsTrivialPropertyAccessor = false;
+break;
   }
 
   if (!HasGetOrSet) {
@@ -1526,33 +1528,51 @@
 return false;
   }
 
+  // Try to parse the property accessor:
+  // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
   Tokens->setPosition(StoredPosition);
-  while (FormatTok->isNot(tok::r_brace)) {
-nextToken();
-  }
-
-  // Try to parse (optional) assignment to default value:
-  // `{ get; set; } = new MyType(defaultValue);`
-  //^^^
-  // There may be some very complicated expressions inside default value
-  // assignment, the simple parse block below will not handle them.
-  // The parse block below would need extending to handle opening parens etc.
-  StoredPosition = Tokens->getPosition();
-  Tok = Tokens->getNextToken();
-  bool NextTokenIsEqual = Tok->is(tok::equal);
-  Tokens->setPosition(StoredPosition);
-
-  if (NextTokenIsEqual) {
-do

[PATCH] D78915: [clang-format] Improved parser for C# properties

2020-04-27 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 260316.
jbcoe added a comment.

Format patch.


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

https://reviews.llvm.org/D78915

Files:
  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
@@ -611,6 +611,64 @@
 public string Name {
   get => _name;
   set => _name = value;
+})",
+   Style);
+
+  // Examples taken from
+  // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
+  verifyFormat(R"(
+// Expression body definitions
+public class SaleItem {
+  public decimal Price {
+get => _cost;
+set => _cost = value;
+  }
+})",
+   Style);
+
+  verifyFormat(R"(
+// Properties with backing fields
+class TimePeriod {
+  public double Hours {
+get { return _seconds / 3600; }
+set {
+  if (value < 0 || value > 24)
+throw new ArgumentOutOfRangeException(
+$"{nameof(value)} must be between 0 and 24.");
+  _seconds = value * 3600;
+}
+  }
+})",
+   Style);
+
+  verifyFormat(R"(
+// Auto-implemented properties
+public class SaleItem {
+  public decimal Price { get; set; }
+})",
+   Style);
+
+  // Add column limit to wrap long lines.
+  Style.ColumnLimit = 100;
+
+  // Examples with assignment to default value.
+  verifyFormat(R"(
+// Long assignment to default value
+class MyClass {
+  public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } =
+  VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
+ DefaultThirdArgument);
+})",
+   Style);
+
+  verifyFormat(R"(
+// Long assignment to default value with expression body
+class MyClass {
+  public override VeryLongNamedTypeIndeed VeryLongNamedValue {
+get => veryLongNamedField;
+set => veryLongNamedField = value;
+  } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
+ DefaultThirdArgument);
 })",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -13,6 +13,7 @@
 //===--===//
 
 #include "UnwrappedLineParser.h"
+#include "FormatToken.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -1495,9 +1496,7 @@
   if (FormatTok->Previous->isNot(tok::identifier))
 return false;
 
-  // Try to parse the property accessor braces and contents:
-  // `{ get; set; } = new MyType(defaultValue);`
-  //  ^
+  // See if we are inside a property accessor.
   //
   // Record the current tokenPosition so that we can advance and
   // reset the current token. `Next` is not set yet so we need
@@ -1506,19 +1505,20 @@
   FormatToken *Tok = Tokens->getNextToken();
 
   bool HasGetOrSet = false;
+  bool IsTrivialPropertyAccessor = true;
   while (!eof()) {
 if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private,
  tok::kw_protected, Keywords.kw_internal, Keywords.kw_get,
  Keywords.kw_set)) {
-  if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set))
+  if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set)) {
 HasGetOrSet = true;
+  }
   Tok = Tokens->getNextToken();
   continue;
 }
-if (Tok->is(tok::r_brace))
-  break;
-Tokens->setPosition(StoredPosition);
-return false;
+if (Tok->isNot(tok::r_brace))
+  IsTrivialPropertyAccessor = false;
+break;
   }
 
   if (!HasGetOrSet) {
@@ -1526,33 +1526,53 @@
 return false;
   }
 
-  Tokens->setPosition(StoredPosition);
-  while (FormatTok->isNot(tok::r_brace)) {
-nextToken();
-  }
-
-  // Try to parse (optional) assignment to default value:
+  // Try to parse the property accessor:
   // `{ get; set; } = new MyType(defaultValue);`
-  //^^^
-  // There may be some very complicated expressions inside default value
-  // assignment, the simple parse block below will not handle them.
-  // The parse block below would need extending to handle opening parens etc.
-  StoredPosition = Tokens->getPosition();
-  Tok = Tokens->getNextToken();
-  bool NextTokenIsEqual = Tok->is(tok::equal);
   Tokens->setPosition(StoredPosition);
-
-  if (NextTokenIsEqual) {
-do {
+  nextToken();
+  do {
+switch (FormatTok->Tok.getKind()) {
+case tok::r_brace:
   nextToken();
-  if (FormatTok->is(tok::semi))
+  if (FormatTok->is(tok::equal)) {
+while (!eof() && FormatTok->isNot(tok::se

[PATCH] D78915: [clang-format] Improved parser for C# properties

2020-04-27 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added reviewers: krasimir, MyDeveloperDay.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Added some examples of properties from Microsoft documentation as test cases.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties

Configuration support will be added in a follow up patch to address whether 
automatic properties are formatted as

  Type MyType { get; set }

or

  Type MyType 
  { get; set }


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78915

Files:
  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
@@ -611,6 +611,64 @@
 public string Name {
   get => _name;
   set => _name = value;
+})",
+   Style);
+
+  // Examples taken from
+  // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
+  verifyFormat(R"(
+// Expression body definitions
+public class SaleItem {
+  public decimal Price {
+get => _cost;
+set => _cost = value;
+  }
+})",
+   Style);
+
+  verifyFormat(R"(
+// Properties with backing fields
+class TimePeriod {
+  public double Hours {
+get { return _seconds / 3600; }
+set {
+  if (value < 0 || value > 24)
+throw new ArgumentOutOfRangeException(
+$"{nameof(value)} must be between 0 and 24.");
+  _seconds = value * 3600;
+}
+  }
+})",
+   Style);
+
+  verifyFormat(R"(
+// Auto-implemented properties
+public class SaleItem {
+  public decimal Price { get; set; }
+})",
+   Style);
+
+  // Add column limit to wrap long lines.
+  Style.ColumnLimit = 100;
+
+  // Examples with assignment to default value.
+  verifyFormat(R"(
+// Long assignment to default value
+class MyClass {
+  public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } =
+  VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
+ DefaultThirdArgument);
+})",
+   Style);
+
+  verifyFormat(R"(
+// Long assignment to default value with expression body
+class MyClass {
+  public override VeryLongNamedTypeIndeed VeryLongNamedValue {
+get => veryLongNamedField;
+set => veryLongNamedField = value;
+  } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
+ DefaultThirdArgument);
 })",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -13,6 +13,7 @@
 //===--===//
 
 #include "UnwrappedLineParser.h"
+#include "FormatToken.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -1495,9 +1496,7 @@
   if (FormatTok->Previous->isNot(tok::identifier))
 return false;
 
-  // Try to parse the property accessor braces and contents:
-  // `{ get; set; } = new MyType(defaultValue);`
-  //  ^
+  // See if we are inside a property accessor.
   //
   // Record the current tokenPosition so that we can advance and
   // reset the current token. `Next` is not set yet so we need
@@ -1506,19 +1505,20 @@
   FormatToken *Tok = Tokens->getNextToken();
 
   bool HasGetOrSet = false;
+  bool IsTrivialPropertyAccessor = true;
   while (!eof()) {
 if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private,
  tok::kw_protected, Keywords.kw_internal, Keywords.kw_get,
  Keywords.kw_set)) {
-  if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set))
+  if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set)) {
 HasGetOrSet = true;
+  }
   Tok = Tokens->getNextToken();
   continue;
 }
-if (Tok->is(tok::r_brace))
-  break;
-Tokens->setPosition(StoredPosition);
-return false;
+if(Tok->isNot(tok::r_brace))
+  IsTrivialPropertyAccessor = false;
+break;
   }
 
   if (!HasGetOrSet) {
@@ -1526,33 +1526,52 @@
 return false;
   }
 
-  Tokens->setPosition(StoredPosition);
-  while (FormatTok->isNot(tok::r_brace)) {
-nextToken();
-  }
-
-  // Try to parse (optional) assignment to default value:
+  // Try to parse the property accessor:
   // `{ get; set; } = new MyType(defaultValue);`
-  //^^^
-  // There may be some very complicated expressions inside default value
-  // assignment, the simple parse block below will not handle them.
-  // The parse block below would need extending to handle opening parens etc.
-  Store

[PATCH] D78909: [clang-format] NFC clang-format the clang-format sources

2020-04-27 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe accepted this revision.
jbcoe added a comment.
This revision is now accepted and ready to land.

Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D78909



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


[PATCH] D78642: [clang-format] Handle C# property accessors when parsing lines

2020-04-23 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked 2 inline comments as done.
jbcoe added inline comments.



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:1344
   addUnwrappedLine();
 FormatTok->Type = TT_FunctionLBrace;
 parseBlock(/*MustBeDeclaration=*/false);

MyDeveloperDay wrote:
> previously set and get would break based on the setting of AfterFunction 
> correct? now I assume it doesn't?
That's right. There's a bunch more work needed here and current/previous 
behaviour is undertested and incorrect. 

I'm focusing on this for the next few days so should get everything working 
well and configurable as we'd like.

MS examples are not very consistent so choice seems like the way forward: 
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#properties



Comment at: clang/unittests/Format/FormatTestCSharp.cpp:249
+   "public string Host { set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "

MyDeveloperDay wrote:
> is this just a personal choice? or based on some rule that it shouldn't break?
> 
> I don't like us changing tests unless we understand otherwise we just keep 
> flip-flopping the style?
Agreed. This was oversight and merits discussion. I'll make this configurable 
in a follow-up patch.

Thanks for taking the time to review/comment.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D78642



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


[PATCH] D78642: [clang-format] Handle C# property accessors when parsing lines

2020-04-22 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 259409.
jbcoe added a comment.

Format patch


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

https://reviews.llvm.org/D78642

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

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -245,13 +245,11 @@
"}");
 
   verifyFormat("[TestMethod]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
"listening on provided host\")]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat(
   "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
Index: clang/lib/Format/UnwrappedLineParser.h
===
--- clang/lib/Format/UnwrappedLineParser.h
+++ clang/lib/Format/UnwrappedLineParser.h
@@ -132,6 +132,7 @@
   void parseCSharpGenericTypeConstraint();
   bool tryToParseLambda();
   bool tryToParseLambdaIntroducer();
+  bool tryToParsePropertyAccessor();
   void tryToParseJSFunction();
   void addUnwrappedLine();
   bool eof() const;
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1334,7 +1334,7 @@
 parseChildBlock();
   break;
 case tok::l_brace:
-  if (!tryToParseBracedList()) {
+  if (!tryToParsePropertyAccessor() && !tryToParseBracedList()) {
 // A block outside of parentheses must be the last part of a
 // structural element.
 // FIXME: Figure out cases where this is not true, and add projections
@@ -1487,6 +1487,75 @@
   } while (!eof());
 }
 
+bool UnwrappedLineParser::tryToParsePropertyAccessor() {
+  assert(FormatTok->is(tok::l_brace));
+  if (!Style.isCSharp())
+return false;
+  // See if it's a property accessor.
+  if (FormatTok->Previous->isNot(tok::identifier))
+return false;
+
+  // Try to parse the property accessor braces and contents:
+  // `{ get; set; } = new MyType(defaultValue);`
+  //  ^
+  //
+  // Record the current tokenPosition so that we can advance and
+  // reset the current token. `Next` is not set yet so we need
+  // another way to advance along the token stream.
+  unsigned int StoredPosition = Tokens->getPosition();
+  FormatToken *Tok = Tokens->getNextToken();
+
+  bool HasGetOrSet = false;
+  while (!eof()) {
+if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private,
+ tok::kw_protected, Keywords.kw_internal, Keywords.kw_get,
+ Keywords.kw_set)) {
+  if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set))
+HasGetOrSet = true;
+  Tok = Tokens->getNextToken();
+  continue;
+}
+if (Tok->is(tok::r_brace))
+  break;
+Tokens->setPosition(StoredPosition);
+return false;
+  }
+
+  if (!HasGetOrSet) {
+Tokens->setPosition(StoredPosition);
+return false;
+  }
+
+  Tokens->setPosition(StoredPosition);
+  while (FormatTok->isNot(tok::r_brace)) {
+nextToken();
+  }
+
+  // Try to parse (optional) assignment to default value:
+  // `{ get; set; } = new MyType(defaultValue);`
+  //^^^
+  // There may be some very complicated expressions inside default value
+  // assignment, the simple parse block below will not handle them.
+  // The parse block below would need extending to handle opening parens etc.
+  StoredPosition = Tokens->getPosition();
+  Tok = Tokens->getNextToken();
+  bool NextTokenIsEqual = Tok->is(tok::equal);
+  Tokens->setPosition(StoredPosition);
+
+  if (NextTokenIsEqual) {
+do {
+  nextToken();
+  if (FormatTok->is(tok::semi))
+break;
+} while (!eof());
+  }
+
+  // Add an unwrapped line for the whole property accessor.
+  nextToken();
+  addUnwrappedLine();
+  return true;
+}
+
 bool UnwrappedLineParser::tryToParseLambda() {
   if (!Style.isCpp()) {
 nextToken();
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -294,13 +294,6 @@
   }
 }
 
-// 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 b

[PATCH] D78642: [clang-format] Handle C# property accessors when parsing lines

2020-04-22 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added reviewers: krasimir, MyDeveloperDay.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Improve C# `{ get; set; } = default;` formatting by handling it in the 
UnwrappedLineParser rather than trying to merge lines later.

Remove old logic to merge lines.

Update tests as formatting output has changed (as intended).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78642

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

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -245,13 +245,11 @@
"}");
 
   verifyFormat("[TestMethod]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
"listening on provided host\")]\n"
-   "public string Host\n"
-   "{ set; get; }");
+   "public string Host { set; get; }");
 
   verifyFormat(
   "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
Index: clang/lib/Format/UnwrappedLineParser.h
===
--- clang/lib/Format/UnwrappedLineParser.h
+++ clang/lib/Format/UnwrappedLineParser.h
@@ -132,6 +132,7 @@
   void parseCSharpGenericTypeConstraint();
   bool tryToParseLambda();
   bool tryToParseLambdaIntroducer();
+  bool tryToParsePropertyAccessor();
   void tryToParseJSFunction();
   void addUnwrappedLine();
   bool eof() const;
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1334,7 +1334,7 @@
 parseChildBlock();
   break;
 case tok::l_brace:
-  if (!tryToParseBracedList()) {
+  if (!tryToParsePropertyAccessor() && !tryToParseBracedList()) {
 // A block outside of parentheses must be the last part of a
 // structural element.
 // FIXME: Figure out cases where this is not true, and add projections
@@ -1487,6 +1487,75 @@
   } while (!eof());
 }
 
+bool UnwrappedLineParser::tryToParsePropertyAccessor() {
+  assert(FormatTok->is(tok::l_brace));
+  if(!Style.isCSharp()) 
+return false;
+  // See if it's a property accessor.
+  if (FormatTok->Previous->isNot(tok::identifier))
+return false;
+
+  // Try to parse the property accessor braces and contents:
+  // `{ get; set; } = new MyType(defaultValue);`
+  //  ^
+  //
+  // Record the current tokenPosition so that we can advance and
+  // reset the current token. `Next` is not set yet so we need
+  // another way to advance along the token stream.
+  unsigned int StoredPosition = Tokens->getPosition();
+  FormatToken *Tok = Tokens->getNextToken();
+
+  bool HasGetOrSet = false;
+  while (!eof()) {
+if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private,
+ tok::kw_protected, Keywords.kw_internal, Keywords.kw_get,
+ Keywords.kw_set)) {
+  if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_set))
+  HasGetOrSet = true;
+  Tok = Tokens->getNextToken();
+  continue;
+}
+if (Tok->is(tok::r_brace))
+  break;
+Tokens->setPosition(StoredPosition);
+return false;
+  }
+
+  if(!HasGetOrSet) {
+Tokens->setPosition(StoredPosition);
+return false;
+  }
+
+  Tokens->setPosition(StoredPosition);
+  while (FormatTok->isNot(tok::r_brace)) {
+nextToken();
+  }
+
+  // Try to parse (optional) assignment to default value:
+  // `{ get; set; } = new MyType(defaultValue);`
+  //^^^
+  // There may be some very complicated expressions inside default value
+  // assignment, the simple parse block below will not handle them.
+  // The parse block below would need extending to handle opening parens etc.
+  StoredPosition = Tokens->getPosition();
+  Tok = Tokens->getNextToken();
+  bool NextTokenIsEqual = Tok->is(tok::equal);
+  Tokens->setPosition(StoredPosition);
+
+  if (NextTokenIsEqual) {
+do {
+  nextToken();
+  if (FormatTok->is(tok::semi))
+break;
+} while (!eof());
+  }
+
+  // Add an unwrapped line for the whole property accessor.
+  nextToken();
+  addUnwrappedLine();
+  return true;
+}
+
 bool UnwrappedLineParser::tryToParseLambda() {
   if (!Style.isCpp()) {
 nextToken();
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormat

[PATCH] D78295: [clang-format] Do not interpret C# deconstruction in a foreach as a cast

2020-04-16 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 258035.
jbcoe added a comment.

Format patch


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

https://reviews.llvm.org/D78295

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -624,6 +624,7 @@
   Style.SpaceBeforeCpp11BracedList = true;
   Style.Cpp11BracedListStyle = false;
   Style.SpacesInContainerLiterals = false;
+  Style.SpaceAfterCStyleCast = false;
 
   verifyFormat(R"(new Car { "Door", 0.1 })", Style);
   verifyFormat(R"(new Car { 0.1, "Door" })", Style);
@@ -642,6 +643,12 @@
 
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
 
+  // Not seen as a C-style cast.
+  verifyFormat(R"(//
+foreach ((A a, B b) in someList) {
+})",
+   Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1775,6 +1775,10 @@
 if (Tok.Next->is(tok::question))
   return false;
 
+// `foreach((A a, B b) in someList)` should not be seen as a cast.
+if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
+  return false;
+
 // Functions which end with decorations like volatile, noexcept are 
unlikely
 // to be casts.
 if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -624,6 +624,7 @@
   Style.SpaceBeforeCpp11BracedList = true;
   Style.Cpp11BracedListStyle = false;
   Style.SpacesInContainerLiterals = false;
+  Style.SpaceAfterCStyleCast = false;
 
   verifyFormat(R"(new Car { "Door", 0.1 })", Style);
   verifyFormat(R"(new Car { 0.1, "Door" })", Style);
@@ -642,6 +643,12 @@
 
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
 
+  // Not seen as a C-style cast.
+  verifyFormat(R"(//
+foreach ((A a, B b) in someList) {
+})",
+   Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1775,6 +1775,10 @@
 if (Tok.Next->is(tok::question))
   return false;
 
+// `foreach((A a, B b) in someList)` should not be seen as a cast.
+if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
+  return false;
+
 // Functions which end with decorations like volatile, noexcept are unlikely
 // to be casts.
 if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D78295: [clang-format] Do not interpret C# deconstruction in a foreach as a cast

2020-04-16 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78295

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -624,6 +624,7 @@
   Style.SpaceBeforeCpp11BracedList = true;
   Style.Cpp11BracedListStyle = false;
   Style.SpacesInContainerLiterals = false;
+  Style.SpaceAfterCStyleCast = false;
 
   verifyFormat(R"(new Car { "Door", 0.1 })", Style);
   verifyFormat(R"(new Car { 0.1, "Door" })", Style);
@@ -642,6 +643,11 @@
 
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
 
+  // Not seen as a C-style cast.
+  verifyFormat(R"(//
+foreach ((A a, B b) in someList) {
+})", Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1775,6 +1775,10 @@
 if (Tok.Next->is(tok::question))
   return false;
 
+// `foreach((A a, B b) in someList)` should not be seen as a cast.
+if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
+  return false;
+
 // Functions which end with decorations like volatile, noexcept are 
unlikely
 // to be casts.
 if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -624,6 +624,7 @@
   Style.SpaceBeforeCpp11BracedList = true;
   Style.Cpp11BracedListStyle = false;
   Style.SpacesInContainerLiterals = false;
+  Style.SpaceAfterCStyleCast = false;
 
   verifyFormat(R"(new Car { "Door", 0.1 })", Style);
   verifyFormat(R"(new Car { 0.1, "Door" })", Style);
@@ -642,6 +643,11 @@
 
   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
 
+  // Not seen as a C-style cast.
+  verifyFormat(R"(//
+foreach ((A a, B b) in someList) {
+})", Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1775,6 +1775,10 @@
 if (Tok.Next->is(tok::question))
   return false;
 
+// `foreach((A a, B b) in someList)` should not be seen as a cast.
+if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
+  return false;
+
 // Functions which end with decorations like volatile, noexcept are unlikely
 // to be casts.
 if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77064: [clang-format] Correct line breaks in C# generic type constraints

2020-03-31 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 253925.
jbcoe added a comment.

Fix failing test by preventing inconsistent states from being constructed where 
canBreak is false and mustBreak is true.


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

https://reviews.llvm.org/D77064

Files:
  clang/lib/Format/ContinuationIndenter.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
@@ -564,7 +564,7 @@
 
 TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
-  
+
   verifyFormat(R"(//
 private MySet[] setPoints = {
   new Point(),
@@ -710,6 +710,15 @@
   IAnotherInterfaceStill {})",
Style);
 
+  Style.ColumnLimit = 50; // Force lines to be wrapped.
+  verifyFormat(R"(//
+class ItemFactory
+where T : new(),
+  IAnInterface,
+  IAnotherInterface,
+  IAnotherInterfaceStill {})",
+   Style);
+
   // In other languages `where` can be used as a normal identifier.
   // This example is in C++!
   verifyFormat(R"(//
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -2340,6 +2340,12 @@
   }
   if (FormatTok->Tok.is(tok::semi))
 return;
+  if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
+addUnwrappedLine();
+nextToken();
+parseCSharpGenericTypeConstraint();
+break;
+  }
   nextToken();
 }
   }
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1060,15 +1060,20 @@
   }
 
   void parseCSharpGenericTypeConstraint() {
+int OpenAngleBracketsCount = 0;
 while (CurrentToken) {
   if (CurrentToken->is(tok::less)) {
 // parseAngle is too greedy and will consume the whole line.
 CurrentToken->Type = TT_TemplateOpener;
+++OpenAngleBracketsCount;
 next();
   } else if (CurrentToken->is(tok::greater)) {
 CurrentToken->Type = TT_TemplateCloser;
+--OpenAngleBracketsCount;
 next();
-  } else if (CurrentToken->is(tok::comma)) {
+  } else if (CurrentToken->is(tok::comma) && OpenAngleBracketsCount == 0) {
+// We allow line breaks after GenericTypeConstraintComma's
+// so do not flag commas in Generics as GenericTypeConstraintComma's.
 CurrentToken->Type = TT_CSharpGenericTypeConstraintComma;
 next();
   } else if (CurrentToken->is(Keywords.kw_where)) {
Index: clang/lib/Format/ContinuationIndenter.cpp
===
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -346,6 +346,11 @@
   Current.startsSequence(TT_SelectorName, tok::colon, tok::caret)) {
 return true;
   }
+  // Avoid producing inconsistent states by requiring breaks where they are not
+  // permitted for C# generic type constraints.
+  if (State.Stack.back().IsCSharpGenericTypeConstraint &&
+  Previous.isNot(TT_CSharpGenericTypeConstraintComma))
+return false;
   if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
(Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) &&
 Style.isCpp() &&


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -564,7 +564,7 @@
 
 TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
-  
+
   verifyFormat(R"(//
 private MySet[] setPoints = {
   new Point(),
@@ -710,6 +710,15 @@
   IAnotherInterfaceStill {})",
Style);
 
+  Style.ColumnLimit = 50; // Force lines to be wrapped.
+  verifyFormat(R"(//
+class ItemFactory
+where T : new(),
+  IAnInterface,
+  IAnotherInterface,
+  IAnotherInterfaceStill {})",
+   Style);
+
   // In other languages `where` can be used as a normal identifier.
   // This example is in C++!
   verifyFormat(R"(//
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -2340,6 +2340,12 @@
   }
   if (FormatTok->Tok.is(tok::semi))
 return;
+  if (Style.isCSharp() && FormatTok->is

[PATCH] D77064: [clang-format] Correct line breaks in C# generic type constraints

2020-03-30 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77064

Files:
  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
@@ -702,12 +702,13 @@
 })",
Style);
 
+  Style.ColumnLimit = 50; // Force lines to be wrapped.
   verifyFormat(R"(//
-class ItemFactory
-where T : new(),
-  IAnInterface,
-  IAnotherInterface,
-  IAnotherInterfaceStill {})",
+class ItemFactory
+where T : new(), 
+  IAnInterface, 
+  IAnotherInterface, 
+  IAnotherInterfaceStill {})",
Style);
 
   // In other languages `where` can be used as a normal identifier.
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -2339,7 +2339,13 @@
   break;
   }
   if (FormatTok->Tok.is(tok::semi))
+return;  
+  if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
+addUnwrappedLine();
+nextToken();
+parseCSharpGenericTypeConstraint();
 return;
+  }
   nextToken();
 }
   }
@@ -2354,6 +2360,11 @@
  /*MunchSemi=*/false);
 }
   }
+  // if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
+  //   addUnwrappedLine();
+  //   nextToken();
+  //   parseCSharpGenericTypeConstraint();
+  // }
   // There is no addUnwrappedLine() here so that we fall through to parsing a
   // structural element afterwards. Thus, in "class A {} n, m;",
   // "} n, m;" will end up in one unwrapped line.
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1060,15 +1060,20 @@
   }
 
   void parseCSharpGenericTypeConstraint() {
+int OpenAngleBracketsCount = 0;
 while (CurrentToken) {
   if (CurrentToken->is(tok::less)) {
 // parseAngle is too greedy and will consume the whole line.
 CurrentToken->Type = TT_TemplateOpener;
+++OpenAngleBracketsCount;
 next();
   } else if (CurrentToken->is(tok::greater)) {
 CurrentToken->Type = TT_TemplateCloser;
+--OpenAngleBracketsCount;
 next();
-  } else if (CurrentToken->is(tok::comma)) {
+  } else if (CurrentToken->is(tok::comma) && OpenAngleBracketsCount==0) {
+// We allow line breaks after GenericTypeConstraintComma's
+// so do not flag commas in Generics as GenericTypeConstraintComma's.
 CurrentToken->Type = TT_CSharpGenericTypeConstraintComma;
 next();
   } else if (CurrentToken->is(Keywords.kw_where)) {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -702,12 +702,13 @@
 })",
Style);
 
+  Style.ColumnLimit = 50; // Force lines to be wrapped.
   verifyFormat(R"(//
-class ItemFactory
-where T : new(),
-  IAnInterface,
-  IAnotherInterface,
-  IAnotherInterfaceStill {})",
+class ItemFactory
+where T : new(), 
+  IAnInterface, 
+  IAnotherInterface, 
+  IAnotherInterfaceStill {})",
Style);
 
   // In other languages `where` can be used as a normal identifier.
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -2339,7 +2339,13 @@
   break;
   }
   if (FormatTok->Tok.is(tok::semi))
+return;  
+  if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
+addUnwrappedLine();
+nextToken();
+parseCSharpGenericTypeConstraint();
 return;
+  }
   nextToken();
 }
   }
@@ -2354,6 +2360,11 @@
  /*MunchSemi=*/false);
 }
   }
+  // if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
+  //   addUnwrappedLine();
+  //   nextToken();
+  //   parseCSharpGenericTypeConstraint();
+  // }
   // There is no addUnwrappedLine() here so that we fall through to parsing a
   // structural element afterwards. Thus, in "class A {} n, m;",
   // "} n, m;" will end up in one unwrapped line.
Index: clang/lib/Format/TokenAnnotator.cpp
=

[PATCH] D76621: [clang-format] No space inserted between commas in C#

2020-03-23 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
krasimir accepted this revision.
This revision is now accepted and ready to land.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76621

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -640,9 +640,12 @@
   verifyFormat(R"(private float[,] Values;)", Style);
   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
 
+  verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
+  verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3015,6 +3015,10 @@
 if (Right.is(TT_CSharpNullConditionalLSquare))
   return false;
 
+// No space between consecutive commas '[,,]'.
+if (Left.is(tok::comma) && Right.is(tok::comma))
+  return false;
+
 // Possible space inside `?[ 0 ]`.
 if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -640,9 +640,12 @@
   verifyFormat(R"(private float[,] Values;)", Style);
   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
 
+  verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
+
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
+  verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3015,6 +3015,10 @@
 if (Right.is(TT_CSharpNullConditionalLSquare))
   return false;
 
+// No space between consecutive commas '[,,]'.
+if (Left.is(tok::comma) && Right.is(tok::comma))
+  return false;
+
 // Possible space inside `?[ 0 ]`.
 if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75760: [clang-format] Do not indent C# array initialisers as continuations

2020-03-23 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 252028.
jbcoe added a comment.

Rebase and update patch.


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

https://reviews.llvm.org/D75760

Files:
  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
@@ -562,6 +562,17 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  
+  verifyFormat(R"(//
+private MySet[] setPoints = {
+  new Point(),
+  new Point(),
+};)",
+   Style);
+}
+
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1460,6 +1460,11 @@
 
   nextToken();
   if (FormatTok->Tok.is(tok::l_brace)) {
+// Block kind should probably be set to BK_BracedInit for any language.
+// C# needs this change to ensure that array initialisers and object
+// initialisers are indented the same way.
+if (Style.isCSharp())
+  FormatTok->BlockKind = BK_BracedInit;
 nextToken();
 parseBracedList();
   } else if (Style.Language == FormatStyle::LK_Proto &&
@@ -1652,7 +1657,7 @@
 bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
   tok::TokenKind ClosingBraceKind) {
   bool HasError = false;
-
+  
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -562,6 +562,17 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  
+  verifyFormat(R"(//
+private MySet[] setPoints = {
+  new Point(),
+  new Point(),
+};)",
+   Style);
+}
+
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1460,6 +1460,11 @@
 
   nextToken();
   if (FormatTok->Tok.is(tok::l_brace)) {
+// Block kind should probably be set to BK_BracedInit for any language.
+// C# needs this change to ensure that array initialisers and object
+// initialisers are indented the same way.
+if (Style.isCSharp())
+  FormatTok->BlockKind = BK_BracedInit;
 nextToken();
 parseBracedList();
   } else if (Style.Language == FormatStyle::LK_Proto &&
@@ -1652,7 +1657,7 @@
 bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
   tok::TokenKind ClosingBraceKind) {
   bool HasError = false;
-
+  
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D76597: [clang-format] Reflow long C# generic type constraints correctly

2020-03-23 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Align sequential generic type constraints on a type.

Indent sequential generic type constraints on different types as continuations.

Do not allow '(' and '<' within a generic type constraint to open new scopes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76597

Files:
  clang/lib/Format/ContinuationIndenter.cpp
  clang/lib/Format/ContinuationIndenter.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestCSharp.cpp

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -687,6 +687,14 @@
   where T : IMyInterface { doThing(); }
 })",
Style);
+
+  verifyFormat(R"(//
+class ItemFactory
+where T : new(),
+  IAnInterface,
+  IAnotherInterface,
+  IAnotherInterfaceStill {})",
+   Style);
 }
 
 } // namespace format
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -3620,6 +3620,9 @@
 if (Left.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon) ||
 Right.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon))
   return false;
+// Only break after commas for generic type constraints.
+if (Line.First->is(TT_CSharpGenericTypeConstraint))
+  return Left.is(TT_CSharpGenericTypeConstraintComma);
   } else if (Style.Language == FormatStyle::LK_Java) {
 if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
  Keywords.kw_implements))
Index: clang/lib/Format/ContinuationIndenter.h
===
--- clang/lib/Format/ContinuationIndenter.h
+++ clang/lib/Format/ContinuationIndenter.h
@@ -208,7 +208,8 @@
 LastOperatorWrapped(true), ContainsLineBreak(false),
 ContainsUnwrappedBuilder(false), AlignColons(true),
 ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false),
-NestedBlockInlined(false), IsInsideObjCArrayLiteral(false) {}
+NestedBlockInlined(false), IsInsideObjCArrayLiteral(false),
+IsCSharpGenericTypeConstraint(false) {}
 
   /// \brief The token opening this parenthesis level, or nullptr if this level
   /// is opened by fake parenthesis.
@@ -329,6 +330,8 @@
   /// array literal.
   bool IsInsideObjCArrayLiteral : 1;
 
+  bool IsCSharpGenericTypeConstraint : 1;
+
   bool operator<(const ParenState &Other) const {
 if (Indent != Other.Indent)
   return Indent < Other.Indent;
@@ -366,6 +369,8 @@
   return ContainsUnwrappedBuilder;
 if (NestedBlockInlined != Other.NestedBlockInlined)
   return NestedBlockInlined;
+if (IsCSharpGenericTypeConstraint != Other.IsCSharpGenericTypeConstraint)
+  return IsCSharpGenericTypeConstraint;
 return false;
   }
 };
Index: clang/lib/Format/ContinuationIndenter.cpp
===
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -634,6 +634,7 @@
 State.Stack.back().NoLineBreak = true;
 
   if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign &&
+  !State.Stack.back().IsCSharpGenericTypeConstraint &&
   Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) &&
   (Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit))
 State.Stack.back().Indent = State.Column + Spaces;
@@ -715,6 +716,8 @@
   } else if (Previous.is(TT_InheritanceColon)) {
 State.Stack.back().Indent = State.Column;
 State.Stack.back().LastSpace = State.Column;
+  } else if (Current.is(TT_CSharpGenericTypeConstraintColon)) {
+State.Stack.back().ColonPos = State.Column;
   } else if (Previous.opensScope()) {
 // If a function has a trailing call, indent all parameters from the
 // opening parenthesis. This avoids confusing indents like:
@@ -924,7 +927,13 @@
 unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
   if (!State.NextToken || !State.NextToken->Previous)
 return 0;
+
   FormatToken &Current = *State.NextToken;
+
+  if (State.Stack.back().IsCSharpGenericTypeConstraint &&
+  Current.isNot(TT_CSharpGenericTypeConstraint))
+return State.Stack.back().ColonPos + 2;
+
   const FormatToken &Previous = *Current.Previous;
   // If we are continuing an expression, we want to use the continuation indent.
   unsigned ContinuationIndent =
@@ -1106,9 +1115,11 @@
   assert(State.Stack.size());
   const FormatToken &Current = *State.NextToken;
 
+  if (Current.is(TT_CSharpGenericTypeConstraint))
+State.Stack.back().IsCSharpGenericTypeConstraint = true;

[PATCH] D75747: [clang-format] Correct indentation for `[key] = value,` entries in C++ object initialisers

2020-03-23 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

That's right David, this typo was fixed in a reverted and re-applied commit: 
https://reviews.llvm.org/D75856, https://reviews.llvm.org/D75747


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75747



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


[PATCH] D76367: [clang-format] Handle C# generic type constraints

2020-03-19 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 251349.
jbcoe added a comment.

Address review comments to move deleted test and remove redundant code.

Redundant call to `parseCSharpGenericTypeConstraint` was used for free 
functions which are not legal in C#.


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

https://reviews.llvm.org/D76367

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

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -628,7 +628,6 @@
   verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
   verifyFormat(R"(private float[,] Values;)", Style);
   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
-  verifyFormat(R"(class ItemFactory where T : new() {})", Style);
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
@@ -673,5 +672,22 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(//
+class ItemFactory
+where T : new() {})", Style);
+
+  verifyFormat(R"(//
+class Dictionary
+where TKey : IComparable
+where TVal : IMyInterface {
+  public void MyMethod(T t)
+  where T : IMyInterface { doThing(); }
+})",
+   Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/UnwrappedLineParser.h
===
--- clang/lib/Format/UnwrappedLineParser.h
+++ clang/lib/Format/UnwrappedLineParser.h
@@ -126,6 +126,10 @@
   void parseJavaScriptEs6ImportExport();
   void parseStatementMacro();
   void parseCSharpAttribute();
+  // Parse a C# generic type constraint: `where T : IComparable`.
+  // See:
+  // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
+  void parseCSharpGenericTypeConstraint();
   bool tryToParseLambda();
   bool tryToParseLambdaIntroducer();
   void tryToParseJSFunction();
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -323,6 +323,24 @@
   addUnwrappedLine();
 }
 
+void UnwrappedLineParser::parseCSharpGenericTypeConstraint() {
+  do {
+switch (FormatTok->Tok.getKind()) {
+case tok::l_brace:
+  return;
+default:
+  if (FormatTok->is(Keywords.kw_where)) {
+addUnwrappedLine();
+nextToken();
+parseCSharpGenericTypeConstraint();
+break;
+  }
+  nextToken();
+  break;
+}
+  } while (!eof());
+}
+
 void UnwrappedLineParser::parseCSharpAttribute() {
   int UnpairedSquareBrackets = 1;
   do {
@@ -1344,6 +1362,12 @@
   parseTryCatch();
   return;
 case tok::identifier: {
+  if (Style.isCSharp() && FormatTok->is(Keywords.kw_where) &&
+  Line->MustBeDeclaration) {
+addUnwrappedLine();
+parseCSharpGenericTypeConstraint();
+break;
+  }
   if (FormatTok->is(TT_MacroBlockEnd)) {
 addUnwrappedLine();
 return;
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -64,6 +64,8 @@
 }
 if (static_cast(Indent) + Offset >= 0)
   Indent += Offset;
+if (Line.First->is(TT_CSharpGenericTypeConstraint))
+  Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
   }
 
   /// Update the indent state given that \p Line indent should be
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1047,6 +1047,11 @@
Keywords.kw___has_include_next)) {
 parseHasInclude();
   }
+  if (Tok->is(Keywords.kw_where) && Tok->Next &&
+  Tok->Next->isNot(tok::l_paren)) {
+Tok->Type = TT_CSharpGenericTypeConstraint;
+parseCSharpGenericTypeConstraint();
+  }
   break;
 default:
   break;
@@ -1054,6 +1059,30 @@
 return true;
   }
 
+  void parseCSharpGenericTypeConstraint() {
+while (CurrentToken) {
+  if (CurrentToken->is(tok::less)) {
+// parseAngle is too greedy and will consume the whole line.
+CurrentToken->Type = TT_TemplateOpener;
+next();
+  } else if (CurrentToken->is(tok::greater)) {
+CurrentToken->Type = TT_TemplateCloser;
+n

[PATCH] D76367: [clang-format] Handle C# generic type constraints

2020-03-18 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Treat each C# generic type constraint, `where T: ...`, as a line.

  

Add C# keyword: where

  

Add Token Types: CSharpGenericTypeConstraint, CSharpGenericTypeConstraintColon, 
CSharpGenericTypeConstraintComma.

This patch does not wrap generic type constraints well, that will be addressed 
in a follow up patch.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76367

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

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -628,7 +628,6 @@
   verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
   verifyFormat(R"(private float[,] Values;)", Style);
   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
-  verifyFormat(R"(class ItemFactory where T : new() {})", Style);
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
@@ -673,5 +672,18 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(//
+class Dictionary
+where TKey : IComparable
+where TVal : IMyInterface {
+  public void MyMethod(T t)
+  where T : IMyInterface { doThing(); }
+})",
+   Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/UnwrappedLineParser.h
===
--- clang/lib/Format/UnwrappedLineParser.h
+++ clang/lib/Format/UnwrappedLineParser.h
@@ -126,6 +126,11 @@
   void parseJavaScriptEs6ImportExport();
   void parseStatementMacro();
   void parseCSharpAttribute();
+  // Parse a C# generic type constraint: `where T : IComparable`.
+  // See:
+  // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
+  // If `ConsumeBrace` is true then the terminating brace is consumed.
+  void parseCSharpGenericTypeConstraint(bool ConsumeBrace = true);
   bool tryToParseLambda();
   bool tryToParseLambdaIntroducer();
   void tryToParseJSFunction();
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -323,6 +323,28 @@
   addUnwrappedLine();
 }
 
+void UnwrappedLineParser::parseCSharpGenericTypeConstraint(bool ConsumeBrace) {
+  do {
+switch (FormatTok->Tok.getKind()) {
+case tok::l_brace:
+  if (ConsumeBrace) {
+nextToken();
+addUnwrappedLine();
+  }
+  return;
+default:
+  if (FormatTok->is(Keywords.kw_where)) {
+addUnwrappedLine();
+nextToken();
+parseCSharpGenericTypeConstraint(ConsumeBrace);
+break;
+  }
+  nextToken();
+  break;
+}
+  } while (!eof());
+}
+
 void UnwrappedLineParser::parseCSharpAttribute() {
   int UnpairedSquareBrackets = 1;
   do {
@@ -1344,6 +1366,12 @@
   parseTryCatch();
   return;
 case tok::identifier: {
+  if (Style.isCSharp() && FormatTok->is(Keywords.kw_where) &&
+  Line->MustBeDeclaration) {
+addUnwrappedLine();
+parseCSharpGenericTypeConstraint(/*ConsumeBrace=*/false);
+break;
+  }
   if (FormatTok->is(TT_MacroBlockEnd)) {
 addUnwrappedLine();
 return;
@@ -2283,6 +2311,10 @@
 continue;
   }
 }
+if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) {
+  addUnwrappedLine();
+  parseCSharpGenericTypeConstraint();
+}
 bool IsNonMacroIdentifier =
 FormatTok->is(tok::identifier) &&
 FormatTok->TokenText != FormatTok->TokenText.upper();
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -64,6 +64,8 @@
 }
 if (static_cast(Indent) + Offset >= 0)
   Indent += Offset;
+if (Line.First->is(TT_CSharpGenericTypeConstraint))
+  Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
   }
 
   /// Update the indent state given that \p Line indent should be
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1047,6 +1047,11 @@
Keywords.kw___ha

[PATCH] D75760: [clang-format] Do not indent C# array initialisers as continuations

2020-03-13 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked an inline comment as done.
jbcoe added inline comments.



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:1443
+if (Style.isCSharp())
+  FormatTok->BlockKind = BK_BracedInit;
 nextToken();

krasimir wrote:
> A more general approach might be to adapt parseBracedList() itself to mark 
> the block kind `BK_BracedInit`:
> https://github.com/llvm/llvm-project/blob/7d2fdd3f6639731284dd8b6b274f01f04fd19215/clang/lib/Format/UnwrappedLineParser.cpp#L1628
> 
> Could you try to see if it will be easy/possible to get the same effect by 
> adapting that?
> If that's hard or has unintended side effects, we can reconsider.
Setting block kind inside parseBracedList() caused test failures outside of C# 
tests.

I was hoping to make this surgical for now, hence the comment.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75760



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


[PATCH] D75983: [clang-format] Improved identification of C# nullables

2020-03-11 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 249596.
jbcoe added a comment.

Fix nits from review.


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

https://reviews.llvm.org/D75983

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -652,6 +652,10 @@
 
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
+
+  verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
+
+  verifyFormat(R"(var x = new MyContainer();)", Style); // Generics.
 }
 
 TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -131,7 +131,7 @@
   }
   if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
   (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
-   Style.Language != FormatStyle::LK_Proto &&
+   !Style.isCSharp() && Style.Language != FormatStyle::LK_Proto &&
Style.Language != FormatStyle::LK_TextProto))
 return false;
   // If a && or || is found and interpreted as a binary operator, this set
@@ -1013,12 +1013,13 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-// `Type? name;` and `Type? name =` can only be nullable types.
+// `Type?)`, `Type?>`, `Type? name;` and `Type? name =` can only be
+// nullable types.
 // Line.MustBeDeclaration will be true for `Type? name;`.
-if (!Contexts.back().IsExpression &&
-(Line.MustBeDeclaration ||
- (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
-  Tok->Next->Next->is(tok::equal {
+if ((!Contexts.back().IsExpression && Line.MustBeDeclaration) ||
+(Tok->Next && Tok->Next->isOneOf(tok::r_paren, tok::greater)) ||
+(Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+ Tok->Next->Next->is(tok::equal))) {
   Tok->Type = TT_CSharpNullable;
   break;
 }
@@ -2969,9 +2970,9 @@
 if (Right.is(TT_CSharpNullable))
   return false;
 
-// Require space after ? in nullable types.
+// Require space after ? in nullable types except in generics and casts.
 if (Left.is(TT_CSharpNullable))
-  return true;
+  return !Right.isOneOf(TT_TemplateCloser, tok::r_paren);
 
 // No space before or after '?.'.
 if (Left.is(TT_CSharpNullConditional) || 
Right.is(TT_CSharpNullConditional))


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -652,6 +652,10 @@
 
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
+
+  verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
+
+  verifyFormat(R"(var x = new MyContainer();)", Style); // Generics.
 }
 
 TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -131,7 +131,7 @@
   }
   if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
   (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
-   Style.Language != FormatStyle::LK_Proto &&
+   !Style.isCSharp() && Style.Language != FormatStyle::LK_Proto &&
Style.Language != FormatStyle::LK_TextProto))
 return false;
   // If a && or || is found and interpreted as a binary operator, this set
@@ -1013,12 +1013,13 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-// `Type? name;` and `Type? name =` can only be nullable types.
+// `Type?)`, `Type?>`, `Type? name;` and `Type? name =` can only be
+// nullable types.
 // Line.MustBeDeclaration will be true for `Type? name;`.
-if (!Contexts.back().IsExpression &&
-(Line.MustBeDeclaration ||
- (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
-  Tok->Next->Next->is(tok::equal {
+if ((!Contexts.back().IsExpression && Line.MustBeDeclaration) ||
+(Tok->Next && Tok->Next->isOneOf(tok::r_paren, tok::greater)) ||
+(Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+ Tok->Next->Next->is(tok::equal))) {

[PATCH] D75984: [clang-format] No space in 'new()' and 'this[Type x]' in C#

2020-03-11 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75984

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -627,6 +627,8 @@
   verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
   verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
   verifyFormat(R"(private float[,] Values;)", Style);
+  verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
+  verifyFormat(R"(class ItemFactory where T : new() {})", Style);
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2931,6 +2931,14 @@
 // interpolated strings. Interpolated strings are merged into a single 
token
 // so cannot have spaces inserted by this function.
 
+// No space between 'this' and '['
+if (Left.is(tok::kw_this) && Right.is(tok::l_square))
+  return false;
+
+// No space between 'new' and '('
+if (Left.is(tok::kw_new) && Right.is(tok::l_paren))
+  return false;
+
 // Space before { (including space within '{ {').
 if (Right.is(tok::l_brace))
   return true;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -627,6 +627,8 @@
   verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
   verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
   verifyFormat(R"(private float[,] Values;)", Style);
+  verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
+  verifyFormat(R"(class ItemFactory where T : new() {})", Style);
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2931,6 +2931,14 @@
 // interpolated strings. Interpolated strings are merged into a single token
 // so cannot have spaces inserted by this function.
 
+// No space between 'this' and '['
+if (Left.is(tok::kw_this) && Right.is(tok::l_square))
+  return false;
+
+// No space between 'new' and '('
+if (Left.is(tok::kw_new) && Right.is(tok::l_paren))
+  return false;
+
 // Space before { (including space within '{ {').
 if (Right.is(tok::l_brace))
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75983: [clang-format] Improved identification of C# nullables

2020-03-11 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Allow '?' inside C# generics.

  

Do not mistake casts like (Type?) as conditional operators.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75983

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -650,6 +650,10 @@
 
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
+
+  verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
+
+  verifyFormat(R"(var x = new MyContainer();)", Style); // Generics.
 }
 
 TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -131,7 +131,7 @@
   }
   if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
   (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
-   Style.Language != FormatStyle::LK_Proto &&
+   !Style.isCSharp() && Style.Language != FormatStyle::LK_Proto &&
Style.Language != FormatStyle::LK_TextProto))
 return false;
   // If a && or || is found and interpreted as a binary operator, this set
@@ -1013,12 +1013,13 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-// `Type? name;` and `Type? name =` can only be nullable types.
+// `Type?)`, `Type?>`, `Type? name;`and `Type? name =` can only be
+// nullable types.
 // Line.MustBeDeclaration will be true for `Type? name;`.
-if (!Contexts.back().IsExpression &&
-(Line.MustBeDeclaration ||
- (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
-  Tok->Next->Next->is(tok::equal {
+if ((!Contexts.back().IsExpression && Line.MustBeDeclaration) ||
+(Tok->Next && Tok->Next->isOneOf(tok::r_paren, tok::greater)) ||
+(Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+ Tok->Next->Next->is(tok::equal))) {
   Tok->Type = TT_CSharpNullable;
   break;
 }
@@ -2961,10 +2962,12 @@
 if (Right.is(TT_CSharpNullable))
   return false;
 
-// Require space after ? in nullable types.
-if (Left.is(TT_CSharpNullable))
+// Require space after ? in nullable types except in generics and casts.
+if (Left.is(TT_CSharpNullable)) {
+  if (Right.isOneOf(TT_TemplateCloser, tok::r_paren))
+return false;
   return true;
-
+}
 // No space before or after '?.'.
 if (Left.is(TT_CSharpNullConditional) || 
Right.is(TT_CSharpNullConditional))
   return false;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -650,6 +650,10 @@
 
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
+
+  verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
+
+  verifyFormat(R"(var x = new MyContainer();)", Style); // Generics.
 }
 
 TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -131,7 +131,7 @@
   }
   if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
   (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
-   Style.Language != FormatStyle::LK_Proto &&
+   !Style.isCSharp() && Style.Language != FormatStyle::LK_Proto &&
Style.Language != FormatStyle::LK_TextProto))
 return false;
   // If a && or || is found and interpreted as a binary operator, this set
@@ -1013,12 +1013,13 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-// `Type? name;` and `Type? name =` can only be nullable types.
+// `Type?)`, `Type?>`, `Type? name;`and `Type? name =` can only be
+// nullable types.
 // Line.MustBeDeclaration will be true for `Type? name;`.
-if (!Contexts.back().IsExpression &&
-(Line.MustBeDeclaration ||
- (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
-  Tok->Next->Next->is(tok::equal {
+if ((!Contexts.back().IsExpressio

[PATCH] D75747: [clang-format] Correct indentation for `[key] = value,` entries in C++ object initialisers

2020-03-09 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 249155.
jbcoe added a comment.

Format code.


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

https://reviews.llvm.org/D75747

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -549,6 +549,15 @@
 private Transformer _transformer = new X.Y {
   Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
   Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
+
+  // Dictionary initialisation.
+  verifyFormat(R"(//
+var myDict = new Dictionary {
+  ["name"] = _donald,
+  ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
+  ["type"] = _duck,
 };)",
Style);
 }
Index: clang/lib/Format/ContinuationIndenter.cpp
===
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -1047,6 +1047,9 @@
   if (NextNonComment->is(TT_ArraySubscriptLSquare)) {
 if (State.Stack.back().StartOfArraySubscripts != 0)
   return State.Stack.back().StartOfArraySubscripts;
+else if (Style.isCSharp()) // C# allows `["key"] = value` inside object
+   // initializers.
+  return State.Stack.back().Indent;
 return ContinuationIndent;
   }
 


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -549,6 +549,15 @@
 private Transformer _transformer = new X.Y {
   Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
   Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
+
+  // Dictionary initialisation.
+  verifyFormat(R"(//
+var myDict = new Dictionary {
+  ["name"] = _donald,
+  ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
+  ["type"] = _duck,
 };)",
Style);
 }
Index: clang/lib/Format/ContinuationIndenter.cpp
===
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -1047,6 +1047,9 @@
   if (NextNonComment->is(TT_ArraySubscriptLSquare)) {
 if (State.Stack.back().StartOfArraySubscripts != 0)
   return State.Stack.back().StartOfArraySubscripts;
+else if (Style.isCSharp()) // C# allows `["key"] = value` inside object
+   // initializers.
+  return State.Stack.back().Indent;
 return ContinuationIndent;
   }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75731: [clang-format] C# does not indent braced initializers as continuations

2020-03-09 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked 2 inline comments as done.
jbcoe added inline comments.



Comment at: clang/unittests/Format/FormatTestCSharp.cpp:544
 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
- new Square {
- Side = 101.1,
- Colour = Colours.Yellow,
- } };)",
+ new Square { Side = 101.1, Colour = Colours.Yellow } 
};)",
Style);

krasimir wrote:
> krasimir wrote:
> > Please add test cases that demonstrate the +2 indent used when breaking 
> > inside C# object initializers.
> Consider also adding an example with a trailing comma if the behavior there 
> can be different than the one without a trailing comma.
The test at L 529 already covers 2 space indent and a trailing comma.


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

https://reviews.llvm.org/D75731



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


[PATCH] D75856: [clang-format] cleanup from D75517

2020-03-09 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 249148.

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

https://reviews.llvm.org/D75856

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -650,8 +650,15 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
   // Do not format array subscript operators as attributes.
-  verifyFormat(R"(if (someThings[index].Contains(myThing)) {)", Style);
-  verifyFormat(R"(if (someThings[i][j][k].Contains(myThing)) {)", Style);
+  verifyFormat(R"(//
+if (someThings[index].Contains(myThing)) {
+})",
+   Style);
+
+  verifyFormat(R"(//
+if (someThings[i][j][k].Contains(myThing)) {
+})",
+   Style);
 }
 
 } // namespace format
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -373,7 +373,7 @@
 if (Tok.Previous && Tok.Previous->is(tok::identifier))
   return false;
 
-// Chains [] in of `identifier[i][j][k]` are not attributes.
+// Chains of [] in `identifier[i][j][k]` are not attributes.
 if (Tok.Previous && Tok.Previous->is(tok::r_square)) {
   auto *MatchingParen = Tok.Previous->MatchingParen;
   if (!MatchingParen || MatchingParen->is(TT_ArraySubscriptLSquare))


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -650,8 +650,15 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
   // Do not format array subscript operators as attributes.
-  verifyFormat(R"(if (someThings[index].Contains(myThing)) {)", Style);
-  verifyFormat(R"(if (someThings[i][j][k].Contains(myThing)) {)", Style);
+  verifyFormat(R"(//
+if (someThings[index].Contains(myThing)) {
+})",
+   Style);
+
+  verifyFormat(R"(//
+if (someThings[i][j][k].Contains(myThing)) {
+})",
+   Style);
 }
 
 } // namespace format
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -373,7 +373,7 @@
 if (Tok.Previous && Tok.Previous->is(tok::identifier))
   return false;
 
-// Chains [] in of `identifier[i][j][k]` are not attributes.
+// Chains of [] in `identifier[i][j][k]` are not attributes.
 if (Tok.Previous && Tok.Previous->is(tok::r_square)) {
   auto *MatchingParen = Tok.Previous->MatchingParen;
   if (!MatchingParen || MatchingParen->is(TT_ArraySubscriptLSquare))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75856: [clang-format] cleanup from D75517

2020-03-09 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fix typo in comment.

Add closing brace to test text.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75856

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -650,8 +650,13 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
   // Do not format array subscript operators as attributes.
-  verifyFormat(R"(if (someThings[index].Contains(myThing)) {)", Style);
-  verifyFormat(R"(if (someThings[i][j][k].Contains(myThing)) {)", Style);
+  verifyFormat(R"(//
+if (someThings[index].Contains(myThing)) {
+})", Style);
+
+  verifyFormat(R"(//
+if (someThings[i][j][k].Contains(myThing)) {
+})", Style);
 }
 
 } // namespace format
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -373,7 +373,7 @@
 if (Tok.Previous && Tok.Previous->is(tok::identifier))
   return false;
 
-// Chains [] in of `identifier[i][j][k]` are not attributes.
+// Chains of [] in `identifier[i][j][k]` are not attributes.
 if (Tok.Previous && Tok.Previous->is(tok::r_square)) {
   auto *MatchingParen = Tok.Previous->MatchingParen;
   if (!MatchingParen || MatchingParen->is(TT_ArraySubscriptLSquare))


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -650,8 +650,13 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
   // Do not format array subscript operators as attributes.
-  verifyFormat(R"(if (someThings[index].Contains(myThing)) {)", Style);
-  verifyFormat(R"(if (someThings[i][j][k].Contains(myThing)) {)", Style);
+  verifyFormat(R"(//
+if (someThings[index].Contains(myThing)) {
+})", Style);
+
+  verifyFormat(R"(//
+if (someThings[i][j][k].Contains(myThing)) {
+})", Style);
 }
 
 } // namespace format
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -373,7 +373,7 @@
 if (Tok.Previous && Tok.Previous->is(tok::identifier))
   return false;
 
-// Chains [] in of `identifier[i][j][k]` are not attributes.
+// Chains of [] in `identifier[i][j][k]` are not attributes.
 if (Tok.Previous && Tok.Previous->is(tok::r_square)) {
   auto *MatchingParen = Tok.Previous->MatchingParen;
   if (!MatchingParen || MatchingParen->is(TT_ArraySubscriptLSquare))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75760: [clang-format] Do not indent C# array initialisers as continuations

2020-03-06 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
jbcoe added a comment.

Needs https://reviews.llvm.org/D75731 and https://reviews.llvm.org/D75747 to be 
merged first.


Flag '= {' as a braced init list when parsing C# code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75760

Files:
  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
@@ -562,6 +562,17 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  
+  verifyFormat(R"(//
+private MySet[] setPoints = {
+  new Point(),
+  new Point(),
+};)",
+   Style);
+}
+
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1436,6 +1436,11 @@
 
   nextToken();
   if (FormatTok->Tok.is(tok::l_brace)) {
+// Block kind should probably be set to BK_BracedInit for any language.
+// C# needs this change to ensure that array initialisers and object
+// initialisers are indented the same way.
+if (Style.isCSharp())
+  FormatTok->BlockKind = BK_BracedInit;
 nextToken();
 parseBracedList();
   } else if (Style.Language == FormatStyle::LK_Proto &&
@@ -1628,7 +1633,7 @@
 bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
   tok::TokenKind ClosingBraceKind) {
   bool HasError = false;
-
+  
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -562,6 +562,17 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  
+  verifyFormat(R"(//
+private MySet[] setPoints = {
+  new Point(),
+  new Point(),
+};)",
+   Style);
+}
+
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1436,6 +1436,11 @@
 
   nextToken();
   if (FormatTok->Tok.is(tok::l_brace)) {
+// Block kind should probably be set to BK_BracedInit for any language.
+// C# needs this change to ensure that array initialisers and object
+// initialisers are indented the same way.
+if (Style.isCSharp())
+  FormatTok->BlockKind = BK_BracedInit;
 nextToken();
 parseBracedList();
   } else if (Style.Language == FormatStyle::LK_Proto &&
@@ -1628,7 +1633,7 @@
 bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
   tok::TokenKind ClosingBraceKind) {
   bool HasError = false;
-
+  
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75760: [clang-format] Do not indent C# array initialisers as continuations

2020-03-06 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

Needs https://reviews.llvm.org/D75731 and https://reviews.llvm.org/D75747 to be 
merged first.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75760



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


[PATCH] D75747: [clang-format] Correct indentation for `[key] = value,` entries in C++ object initialisers

2020-03-06 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
jbcoe added a comment.

Requires https://reviews.llvm.org/D75731 to be merged first.


Do not use continuation indent for '[' in blocks in C# code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75747

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -549,6 +549,15 @@
 private Transformer _transformer = new X.Y {
   Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
   Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
+
+  // Dictionary initialisation.
+  verifyFormat(R"(//
+var myDict = new Dictionary {
+  ["name"] = _donald,
+  ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
+  ["type"] = _duck,
 };)",
Style);
 }
Index: clang/lib/Format/ContinuationIndenter.cpp
===
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -1047,6 +1047,8 @@
   if (NextNonComment->is(TT_ArraySubscriptLSquare)) {
 if (State.Stack.back().StartOfArraySubscripts != 0)
   return State.Stack.back().StartOfArraySubscripts;
+else if (Style.isCSharp()) // C# allows `["key"] = value` inside object 
initializers.
+  return State.Stack.back().Indent;
 return ContinuationIndent;
   }
 


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -549,6 +549,15 @@
 private Transformer _transformer = new X.Y {
   Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
   Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
+
+  // Dictionary initialisation.
+  verifyFormat(R"(//
+var myDict = new Dictionary {
+  ["name"] = _donald,
+  ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
+  ["type"] = _duck,
 };)",
Style);
 }
Index: clang/lib/Format/ContinuationIndenter.cpp
===
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -1047,6 +1047,8 @@
   if (NextNonComment->is(TT_ArraySubscriptLSquare)) {
 if (State.Stack.back().StartOfArraySubscripts != 0)
   return State.Stack.back().StartOfArraySubscripts;
+else if (Style.isCSharp()) // C# allows `["key"] = value` inside object initializers.
+  return State.Stack.back().Indent;
 return ContinuationIndent;
   }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75747: [clang-format] Correct indentation for `[key] = value,` entries in C++ object initialisers

2020-03-06 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

Requires https://reviews.llvm.org/D75731 to be merged first.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75747



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


[PATCH] D75731: [clang-format] C# does not indent braced initializers as continuations

2020-03-06 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 248719.
jbcoe added a comment.

Remove comma to tidy up ugly format test and actually test what is needed.


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

https://reviews.llvm.org/D75731

Files:
  clang/lib/Format/FormatToken.h
  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
@@ -527,31 +527,28 @@
 
   verifyFormat(R"(//
 Shape[] shapes = new[] {
-new Circle {
-Radius = 2.7281,
-Colour = Colours.Red,
-},
-new Square {
-Side = 101.1,
-Colour = Colours.Yellow,
-},
+  new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+  },
+  new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+  },
 };)",
Style);
 
   // 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,
- } };)",
+ new Square { Side = 101.1, Colour = Colours.Yellow } 
};)",
Style);
 
   // Lambdas can be supplied as initialiser arguments.
   verifyFormat(R"(//
 private Transformer _transformer = new X.Y {
-Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
-Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+  Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+  Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
 };)",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1677,7 +1677,10 @@
   }
   break;
 case tok::l_square:
-  tryToParseLambda();
+  if (Style.isCSharp())
+parseSquare();
+  else
+tryToParseLambda();
   break;
 case tok::l_paren:
   parseParens();
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -509,6 +509,9 @@
   /// Returns \c true if this tokens starts a block-type list, i.e. a
   /// list that should be indented with a block indent.
   bool opensBlockOrBlockTypeList(const FormatStyle &Style) const {
+// C# Does not indent object initialisers as continuations.
+if (is(tok::l_brace) && BlockKind == BK_BracedInit && Style.isCSharp())
+  return true;
 if (is(TT_TemplateString) && opensScope())
   return true;
 return is(TT_ArrayInitializerLSquare) || is(TT_ProtoExtensionLSquare) ||


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -527,31 +527,28 @@
 
   verifyFormat(R"(//
 Shape[] shapes = new[] {
-new Circle {
-Radius = 2.7281,
-Colour = Colours.Red,
-},
-new Square {
-Side = 101.1,
-Colour = Colours.Yellow,
-},
+  new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+  },
+  new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+  },
 };)",
Style);
 
   // 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,
- } };)",
+ new Square { Side = 101.1, Colour = Colours.Yellow } };)",
Style);
 
   // Lambdas can be supplied as initialiser arguments.
   verifyFormat(R"(//
 private Transformer _transformer = new X.Y {
-Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
-Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+  Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+  Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
 };)",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1677,7 +1677,10 @@
   }
   break;
 case tok::l_square:
-  tryToParseLambda();
+  if (Style.isCSharp())
+parseSquare();
+  else
+tryToParseLambda();
   break;
   

[PATCH] D75731: [clang-format] C# does not indent braced initializers as continuations

2020-03-06 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 248712.

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

https://reviews.llvm.org/D75731

Files:
  clang/lib/Format/FormatToken.h
  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
@@ -527,31 +527,31 @@
 
   verifyFormat(R"(//
 Shape[] shapes = new[] {
-new Circle {
-Radius = 2.7281,
-Colour = Colours.Red,
-},
-new Square {
-Side = 101.1,
-Colour = Colours.Yellow,
-},
+  new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+  },
+  new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+  },
 };)",
Style);
 
   // 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);
 
   // Lambdas can be supplied as initialiser arguments.
   verifyFormat(R"(//
 private Transformer _transformer = new X.Y {
-Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
-Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+  Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+  Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
 };)",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1677,7 +1677,10 @@
   }
   break;
 case tok::l_square:
-  tryToParseLambda();
+  if (Style.isCSharp())
+parseSquare();
+  else
+tryToParseLambda();
   break;
 case tok::l_paren:
   parseParens();
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -509,6 +509,9 @@
   /// Returns \c true if this tokens starts a block-type list, i.e. a
   /// list that should be indented with a block indent.
   bool opensBlockOrBlockTypeList(const FormatStyle &Style) const {
+// C# Does not indent object initialisers as continuations.
+if (is(tok::l_brace) && BlockKind == BK_BracedInit && Style.isCSharp())
+  return true;
 if (is(TT_TemplateString) && opensScope())
   return true;
 return is(TT_ArrayInitializerLSquare) || is(TT_ProtoExtensionLSquare) ||


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -527,31 +527,31 @@
 
   verifyFormat(R"(//
 Shape[] shapes = new[] {
-new Circle {
-Radius = 2.7281,
-Colour = Colours.Red,
-},
-new Square {
-Side = 101.1,
-Colour = Colours.Yellow,
-},
+  new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+  },
+  new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+  },
 };)",
Style);
 
   // 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);
 
   // Lambdas can be supplied as initialiser arguments.
   verifyFormat(R"(//
 private Transformer _transformer = new X.Y {
-Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
-Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+  Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+  Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
 };)",
Style);
 }
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1677,7 +1677,10 @@
   }
   break;
 case tok::l_square:
-  tryToParseLambda();
+  if (S

[PATCH] D75731: [clang-format] C# does not indent braced initializers as continuations

2020-03-06 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

C# treats object initializers as braced init blocks. Braced init blocks are no 
longer indented as continuations.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75731

Files:
  clang/lib/Format/ContinuationIndenter.cpp
  clang/lib/Format/FormatToken.h
  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
@@ -527,14 +527,14 @@
 
   verifyFormat(R"(//
 Shape[] shapes = new[] {
-new Circle {
-Radius = 2.7281,
-Colour = Colours.Red,
-},
-new Square {
-Side = 101.1,
-Colour = Colours.Yellow,
-},
+  new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+  },
+  new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+  },
 };)",
Style);
 
@@ -542,8 +542,8 @@
   verifyFormat(R"(//
 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
  new Square {
- Side = 101.1,
- Colour = Colours.Yellow,
+   Side = 101.1,
+   Colour = Colours.Yellow,
  } };)",
Style);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1677,7 +1677,10 @@
   }
   break;
 case tok::l_square:
-  tryToParseLambda();
+  if (Style.isCSharp())
+parseSquare();
+  else
+tryToParseLambda();
   break;
 case tok::l_paren:
   parseParens();
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -509,6 +509,9 @@
   /// Returns \c true if this tokens starts a block-type list, i.e. a
   /// list that should be indented with a block indent.
   bool opensBlockOrBlockTypeList(const FormatStyle &Style) const {
+// C# Does not indent object initialisers as continuations.
+if (is(tok::l_brace) && BlockKind == BK_BracedInit && Style.isCSharp())
+  return true;
 if (is(TT_TemplateString) && opensScope())
   return true;
 return is(TT_ArrayInitializerLSquare) || is(TT_ProtoExtensionLSquare) ||
Index: clang/lib/Format/ContinuationIndenter.cpp
===
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -1047,6 +1047,9 @@
   if (NextNonComment->is(TT_ArraySubscriptLSquare)) {
 if (State.Stack.back().StartOfArraySubscripts != 0)
   return State.Stack.back().StartOfArraySubscripts;
+// C# allows `["Key"] = value,` in braced init lists (Object initializers).
+if (State.Stack.back().Tok->BlockKind == BK_BracedInit && Style.isCSharp())
+  return State.Stack.back().Indent;
 return ContinuationIndent;
   }
 


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -527,14 +527,14 @@
 
   verifyFormat(R"(//
 Shape[] shapes = new[] {
-new Circle {
-Radius = 2.7281,
-Colour = Colours.Red,
-},
-new Square {
-Side = 101.1,
-Colour = Colours.Yellow,
-},
+  new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+  },
+  new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+  },
 };)",
Style);
 
@@ -542,8 +542,8 @@
   verifyFormat(R"(//
 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
  new Square {
- Side = 101.1,
- Colour = Colours.Yellow,
+   Side = 101.1,
+   Colour = Colours.Yellow,
  } };)",
Style);
 
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1677,7 +1677,10 @@
   }
   break;
 case tok::l_square:
-  tryToParseLambda();
+  if (Style.isCSharp())
+parseSquare();
+  else
+tryToParseLambda();
   break;
 case tok::l_paren:
   parseParens();
Index: clang/lib/Format/FormatToken.h
===
--- clang/li

[PATCH] D75606: [clang-format] Improve identification of C# nullables

2020-03-04 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 248232.
jbcoe marked an inline comment as done.
jbcoe added a comment.

Remove duplicate check following review comment.


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

https://reviews.llvm.org/D75606

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -631,7 +631,17 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.SpacesInSquareBrackets = false;
 
+  verifyFormat(R"(//
+public class A {
+  void foo() { int? value = some.bar(); }
+})",
+   Style); // int? is nullable not a conditional expression.
+
+  verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
+   Style); // Nullables in function definitions.
+
   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
 }
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1011,7 +1011,12 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-if (Line.MustBeDeclaration && !Contexts.back().IsExpression) {
+// `Type? name;` and `Type? name =` can only be nullable types.
+// Line.MustBeDeclaration will be true for `Type? name;`.
+if (!Contexts.back().IsExpression &&
+(Line.MustBeDeclaration ||
+ (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+  Tok->Next->Next->is(tok::equal {
   Tok->Type = TT_CSharpNullable;
   break;
 }


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -631,7 +631,17 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.SpacesInSquareBrackets = false;
 
+  verifyFormat(R"(//
+public class A {
+  void foo() { int? value = some.bar(); }
+})",
+   Style); // int? is nullable not a conditional expression.
+
+  verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
+   Style); // Nullables in function definitions.
+
   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
 }
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1011,7 +1011,12 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-if (Line.MustBeDeclaration && !Contexts.back().IsExpression) {
+// `Type? name;` and `Type? name =` can only be nullable types.
+// Line.MustBeDeclaration will be true for `Type? name;`.
+if (!Contexts.back().IsExpression &&
+(Line.MustBeDeclaration ||
+ (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+  Tok->Next->Next->is(tok::equal {
   Tok->Type = TT_CSharpNullable;
   break;
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75606: [clang-format] Improve identification of C# nullables

2020-03-04 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Consider `? identifier =` and `? identifier;` to be nullable within function 
bodies.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75606

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -631,7 +631,17 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.SpacesInSquareBrackets = false;
 
+  verifyFormat(R"(//
+public class A {
+  void foo() { int? value = some.bar(); }
+})",
+   Style); // int? is nullable not a conditional expression.
+
+  verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
+   Style); // Nullables in function definitions.
+
   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
 }
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1011,7 +1011,11 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-if (Line.MustBeDeclaration && !Contexts.back().IsExpression) {
+// `Type? name;` and `Type? name =` can only be nullable types.
+if (!Contexts.back().IsExpression &&
+(Line.MustBeDeclaration ||
+ (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+  Tok->Next->Next->isOneOf(tok::equal, tok::semi {
   Tok->Type = TT_CSharpNullable;
   break;
 }


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -631,7 +631,17 @@
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.SpacesInSquareBrackets = false;
 
+  verifyFormat(R"(//
+public class A {
+  void foo() { int? value = some.bar(); }
+})",
+   Style); // int? is nullable not a conditional expression.
+
+  verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
+   Style); // Nullables in function definitions.
+
   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+
   verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
 }
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1011,7 +1011,11 @@
   Style.Language == FormatStyle::LK_JavaScript)
 break;
   if (Style.isCSharp()) {
-if (Line.MustBeDeclaration && !Contexts.back().IsExpression) {
+// `Type? name;` and `Type? name =` can only be nullable types.
+if (!Contexts.back().IsExpression &&
+(Line.MustBeDeclaration ||
+ (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+  Tok->Next->Next->isOneOf(tok::equal, tok::semi {
   Tok->Type = TT_CSharpNullable;
   break;
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75473: [clang-format] parse C# object initialisers

2020-03-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 248039.
jbcoe added a comment.

Remove code without test coverage.


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

https://reviews.llvm.org/D75473

Files:
  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
@@ -546,6 +546,14 @@
  Colour = Colours.Yellow,
  } };)",
Style);
+
+  // Lambdas can be supplied as initialiser arguments.
+  verifyFormat(R"(//
+private Transformer _transformer = new X.Y {
+Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1632,6 +1632,17 @@
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {
+if (Style.isCSharp()) {
+  if (FormatTok->is(TT_JsFatArrow)) {
+nextToken();
+// Fat arrows can be followed by simple expressions or by child blocks
+// in curly braces.
+if (FormatTok->is(tok::l_brace)) {
+  parseChildBlock();
+  continue;
+}
+  }
+}
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (FormatTok->is(Keywords.kw_function) ||
   FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) {
@@ -1955,7 +1966,7 @@
  DeclarationScopeStack.size() > 1);
 parseBlock(/*MustBeDeclaration=*/true, AddLevel);
 // Munch the semicolon after a namespace. This is more common than one 
would
-// think. Puttin the semicolon into its own line is very ugly.
+// think. Putting the semicolon into its own line is very ugly.
 if (FormatTok->Tok.is(tok::semi))
   nextToken();
 addUnwrappedLine();
@@ -1966,6 +1977,19 @@
 void UnwrappedLineParser::parseNew() {
   assert(FormatTok->is(tok::kw_new) && "'new' expected");
   nextToken();
+
+  if (Style.isCSharp()) {
+do {
+  if (FormatTok->is(tok::l_brace))
+parseBracedList();
+
+  if (FormatTok->isOneOf(tok::semi, tok::comma))
+return;
+
+  nextToken();
+} while (!eof());
+  }
+
   if (Style.Language != FormatStyle::LK_Java)
 return;
 


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -546,6 +546,14 @@
  Colour = Colours.Yellow,
  } };)",
Style);
+
+  // Lambdas can be supplied as initialiser arguments.
+  verifyFormat(R"(//
+private Transformer _transformer = new X.Y {
+Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1632,6 +1632,17 @@
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {
+if (Style.isCSharp()) {
+  if (FormatTok->is(TT_JsFatArrow)) {
+nextToken();
+// Fat arrows can be followed by simple expressions or by child blocks
+// in curly braces.
+if (FormatTok->is(tok::l_brace)) {
+  parseChildBlock();
+  continue;
+}
+  }
+}
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (FormatTok->is(Keywords.kw_function) ||
   FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) {
@@ -1955,7 +1966,7 @@
  DeclarationScopeStack.size() > 1);
 parseBlock(/*MustBeDeclaration=*/true, AddLevel);
 // Munch the semicolon after a namespace. This is more common than one would
-// think. Puttin the semicolon into its own line is very ugly.
+// think. Putting the semicolon into its own line is very ugly.
 if (FormatTok->Tok.is(tok::semi))
   nextToken();
 addUnwrappedLine();
@@ -1966,6 +1977,19 @@
 void UnwrappedLineParser::parseNew() {
   assert(FormatTok->is(tok::kw_new) && "'new' expected");
   nextToken();
+
+  if (Style.isCSharp()) {
+do {
+  if

[PATCH] D75473: [clang-format] parse C# object initialisers

2020-03-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked an inline comment as done.
jbcoe added inline comments.



Comment at: clang/lib/Format/UnwrappedLineParser.cpp:1978
+  if (FormatTok->is(tok::l_paren))
+parseParens();
+

krasimir wrote:
> I don't understand why this is needed, and removing this `if` does not cause 
> any tests to fail.
> Please add a test case that will fail if we remove this `if`, or consider 
> removing otherwise.
I'll remove this for now and put together a follow up patch with test cases for 
more obscure object initializer use cases.


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

https://reviews.llvm.org/D75473



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


[PATCH] D75517: [clang-format] Do not format C# array subscript operators as attributes

2020-03-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fix misidentification of C# array subscript operators.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75517

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -619,5 +619,13 @@
Style); // An array of a nullable type.
 }
 
+TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  // Do not format array subscript operators as attributes.
+  verifyFormat(R"(if (someThings[index].Contains(myThing)) {)", Style);
+  verifyFormat(R"(if (someThings[i][j][k].Contains(myThing)) {)", Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -369,6 +369,17 @@
 if (!Style.isCSharp())
   return false;
 
+// `identifier[i]` is not an attribute.
+if (Tok.Previous && Tok.Previous->is(tok::identifier))
+  return false;
+
+// Chains [] in of `identifier[i][j][k]` are not attributes.
+if (Tok.Previous && Tok.Previous->is(tok::r_square)) {
+  auto *MatchingParen = Tok.Previous->MatchingParen;
+  if (!MatchingParen || MatchingParen->is(TT_ArraySubscriptLSquare))
+return false;
+}
+
 const FormatToken *AttrTok = Tok.Next;
 if (!AttrTok)
   return false;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -619,5 +619,13 @@
Style); // An array of a nullable type.
 }
 
+TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  // Do not format array subscript operators as attributes.
+  verifyFormat(R"(if (someThings[index].Contains(myThing)) {)", Style);
+  verifyFormat(R"(if (someThings[i][j][k].Contains(myThing)) {)", Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -369,6 +369,17 @@
 if (!Style.isCSharp())
   return false;
 
+// `identifier[i]` is not an attribute.
+if (Tok.Previous && Tok.Previous->is(tok::identifier))
+  return false;
+
+// Chains [] in of `identifier[i][j][k]` are not attributes.
+if (Tok.Previous && Tok.Previous->is(tok::r_square)) {
+  auto *MatchingParen = Tok.Previous->MatchingParen;
+  if (!MatchingParen || MatchingParen->is(TT_ArraySubscriptLSquare))
+return false;
+}
+
 const FormatToken *AttrTok = Tok.Next;
 if (!AttrTok)
   return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75465: [clang-format] Do not merge target-name and : for C# attributes

2020-03-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 247832.
jbcoe marked 2 inline comments as done.
jbcoe added a comment.

Do not allow spaces around C# attribute colons.


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

https://reviews.llvm.org/D75465

Files:
  clang/lib/Format/FormatTokenLexer.cpp
  clang/lib/Format/FormatTokenLexer.h
  clang/lib/Format/TokenAnnotator.cpp

Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -384,11 +384,11 @@
 
 if (!AttrTok)
   return false;
-
-// Move past the end of ']'.
+
+// Allow an attribute to be the only content of a file.
 AttrTok = AttrTok->Next;
 if (!AttrTok)
-  return false;
+  return true;
 
 // Limit this to being an access modifier that follows.
 if (AttrTok->isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
@@ -460,7 +460,7 @@
  Contexts.back().InCpp11AttributeSpecifier;
 
 // Treat C# Attributes [STAThread] much like C++ attributes [[...]].
-bool IsCSharp11AttributeSpecifier =
+bool IsCSharpAttributeSpecifier =
 isCSharpAttributeSpecifier(*Left) ||
 Contexts.back().InCSharpAttributeSpecifier;
 
@@ -469,7 +469,8 @@
 bool StartsObjCMethodExpr =
 !IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
 Style.isCpp() && !IsCpp11AttributeSpecifier &&
-Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
+!IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression &&
+Left->isNot(TT_LambdaLSquare) &&
 !CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
 (!Parent ||
  Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
@@ -496,7 +497,7 @@
   } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
  Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
 Left->Type = TT_DesignatedInitializerLSquare;
-  } else if (IsCSharp11AttributeSpecifier) {
+  } else if (IsCSharpAttributeSpecifier) {
 Left->Type = TT_AttributeSquare;
   } else if (CurrentToken->is(tok::r_square) && Parent &&
  Parent->is(TT_TemplateCloser)) {
@@ -559,13 +560,13 @@
 
 Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr;
 Contexts.back().InCpp11AttributeSpecifier = IsCpp11AttributeSpecifier;
-Contexts.back().InCSharpAttributeSpecifier = IsCSharp11AttributeSpecifier;
+Contexts.back().InCSharpAttributeSpecifier = IsCSharpAttributeSpecifier;
 
 while (CurrentToken) {
   if (CurrentToken->is(tok::r_square)) {
 if (IsCpp11AttributeSpecifier)
   CurrentToken->Type = TT_AttributeSquare;
-if (IsCSharp11AttributeSpecifier)
+if (IsCSharpAttributeSpecifier)
   CurrentToken->Type = TT_AttributeSquare;
 else if (((CurrentToken->Next &&
CurrentToken->Next->is(tok::l_paren)) ||
@@ -777,6 +778,10 @@
   break;
 }
   } else if (Style.isCSharp()) {
+if (Contexts.back().InCSharpAttributeSpecifier) {
+  Tok->Type = TT_AttributeColon;
+  break;
+}
 if (Contexts.back().ContextKind == tok::l_paren) {
   Tok->Type = TT_CSharpNamedArgumentColon;
   break;
@@ -2922,6 +2927,10 @@
 if (Left.is(TT_JsFatArrow) || Right.is(TT_JsFatArrow))
   return true;
 
+// No spaces around attribute target colons
+if (Left.is(TT_AttributeColon) || Right.is(TT_AttributeColon))
+  return false;
+
 // space between type and variable e.g. Dictionary foo;
 if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
   return true;
@@ -3550,8 +3559,8 @@
   const FormatToken &Left = *Right.Previous;
   // Language-specific stuff.
   if (Style.isCSharp()) {
-if (Left.is(TT_CSharpNamedArgumentColon) ||
-Right.is(TT_CSharpNamedArgumentColon))
+if (Left.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon) ||
+Right.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon))
   return false;
   } else if (Style.Language == FormatStyle::LK_Java) {
 if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
Index: clang/lib/Format/FormatTokenLexer.h
===
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -55,7 +55,6 @@
   bool tryMergeCSharpDoubleQuestion();
   bool tryMergeCSharpNullConditional();
   bool tryTransformCSharpForEach();
-  bool tryMergeCSharpAttributeAndTarget();
 
   bool tryMergeTokens(ArrayRef Kinds, TokenType NewType);
 
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -76,8 +76,6 @@
 return;
 
   if (Styl

[PATCH] D75465: [clang-format] Do not merge target-name and : for C# attributes

2020-03-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added inline comments.



Comment at: clang/lib/Format/TokenAnnotator.cpp:391
 if (!AttrTok)
-  return false;
+  return true;
 

This is needed to avoid 

```
[assembly:InternalsVisibleTo("SomeAssembly, 
PublicKey=SomePublicKeyThatExceedsTheColumnLimit")]
```

being classified as a ObjCMethodExpr (as seen when running clang-format with 
-debug).

The formatting results are currently the same for ObjCMethodExpr and 
CSharpAttributes.



Comment at: clang/unittests/Format/FormatTestCSharp.cpp:281
   Style.ColumnLimit = 10;
-  verifyFormat(R"([assembly:InternalsVisibleTo(
+  verifyFormat(R"([assembly: InternalsVisibleTo(
 "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])",

krasimir wrote:
> krasimir wrote:
> > isn't the space after the `:` a regression?
> > Looking at
> > https://docs.microsoft.com/en-us/dotnet/standard/assembly/set-attributes
> > it looks like such attributes are spelled `[assembly:Blah]`
> > 
> > How is an example where such an attribute is not the last thing in the file?
> > 
> > I'm not entirely clear on which edit caused this.
> The space maybe is coming from
> [[ 
> https://github.com/llvm/llvm-project/blob/ff9f4b5489cda4d9b31595b54ec0296dc012588d/clang/lib/Format/TokenAnnotator.h#L177
>  | TokenAnnotator.spaceRequiredBetween ]], which may need to be adjusted for 
> C#.
There seems to be some inconsistency between the docs you linked (which has no 
space) and code that forms part of projects like Roslyn (which has the space).

I'll defer making this change (if we want it until later).


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

https://reviews.llvm.org/D75465



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


[PATCH] D75194: [clang-format] Do not merge very long C# automatic properties

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe planned changes to this revision.
jbcoe added a comment.

I will try to handle this in unwrapped line parser.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75194



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


[PATCH] D75473: [clang-format] parse C# object initialisers

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Treat C# object initializers as braced lists.

Allow lambdas inside C# braced lists.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75473

Files:
  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
@@ -537,6 +537,14 @@
  Colour = Colours.Yellow,
  } };)",
Style);
+
+  // Lambdas can be supplied as initialiser arguments.
+  verifyFormat(R"(//
+private Transformer _transformer = new X.Y {
+Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1623,6 +1623,17 @@
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {
+if (Style.isCSharp()) {
+  if (FormatTok->is(TT_JsFatArrow)) {
+nextToken();
+// Fat arrows can be followed by simple expressions or by child blocks
+// in curly braces.
+if (FormatTok->is(tok::l_brace)) {
+  parseChildBlock();
+  continue;
+}
+  }
+}
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (FormatTok->is(Keywords.kw_function) ||
   FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) {
@@ -1946,7 +1957,7 @@
  DeclarationScopeStack.size() > 1);
 parseBlock(/*MustBeDeclaration=*/true, AddLevel);
 // Munch the semicolon after a namespace. This is more common than one 
would
-// think. Puttin the semicolon into its own line is very ugly.
+// think. Putting the semicolon into its own line is very ugly.
 if (FormatTok->Tok.is(tok::semi))
   nextToken();
 addUnwrappedLine();
@@ -1957,6 +1968,22 @@
 void UnwrappedLineParser::parseNew() {
   assert(FormatTok->is(tok::kw_new) && "'new' expected");
   nextToken();
+
+  if (Style.isCSharp()) {
+do {
+  if (FormatTok->is(tok::l_brace))
+parseBracedList();
+
+  if (FormatTok->is(tok::l_paren))
+parseParens();
+
+  if (FormatTok->isOneOf(tok::semi, tok::comma))
+return;
+
+  nextToken();
+} while (!eof());
+  }
+
   if (Style.Language != FormatStyle::LK_Java)
 return;
 


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -537,6 +537,14 @@
  Colour = Colours.Yellow,
  } };)",
Style);
+
+  // Lambdas can be supplied as initialiser arguments.
+  verifyFormat(R"(//
+private Transformer _transformer = new X.Y {
+Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
+Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
+};)",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -1623,6 +1623,17 @@
   // FIXME: Once we have an expression parser in the UnwrappedLineParser,
   // replace this by using parseAssigmentExpression() inside.
   do {
+if (Style.isCSharp()) {
+  if (FormatTok->is(TT_JsFatArrow)) {
+nextToken();
+// Fat arrows can be followed by simple expressions or by child blocks
+// in curly braces.
+if (FormatTok->is(tok::l_brace)) {
+  parseChildBlock();
+  continue;
+}
+  }
+}
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (FormatTok->is(Keywords.kw_function) ||
   FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) {
@@ -1946,7 +1957,7 @@
  DeclarationScopeStack.size() > 1);
 parseBlock(/*MustBeDeclaration=*/true, AddLevel);
 // Munch the semicolon after a namespace. This is more common than one would
-// think. Puttin the semicolon into its own line is very ugly.
+// think. Putting the semicolon into its own line is very ugly.
 if (FormatTok->Tok.is(tok::semi))
   nextToken();
 addUnwrappedL

[PATCH] D75465: [clang-format] Do not merge target-name and : for C# attributes

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Re-use token type `TT_AttributeColon` for C# attribute target colons.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75465

Files:
  clang/lib/Format/FormatTokenLexer.cpp
  clang/lib/Format/FormatTokenLexer.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestCSharp.cpp

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -278,7 +278,7 @@
   // Modify Style to enforce a column limit.
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.ColumnLimit = 10;
-  verifyFormat(R"([assembly:InternalsVisibleTo(
+  verifyFormat(R"([assembly: InternalsVisibleTo(
 "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])",
Style);
 }
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -384,11 +384,11 @@
 
 if (!AttrTok)
   return false;
-
-// Move past the end of ']'.
+
+// Allow an attribute to be the only content of a file.
 AttrTok = AttrTok->Next;
 if (!AttrTok)
-  return false;
+  return true;
 
 // Limit this to being an access modifier that follows.
 if (AttrTok->isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
@@ -460,7 +460,7 @@
  Contexts.back().InCpp11AttributeSpecifier;
 
 // Treat C# Attributes [STAThread] much like C++ attributes [[...]].
-bool IsCSharp11AttributeSpecifier =
+bool IsCSharpAttributeSpecifier =
 isCSharpAttributeSpecifier(*Left) ||
 Contexts.back().InCSharpAttributeSpecifier;
 
@@ -469,7 +469,8 @@
 bool StartsObjCMethodExpr =
 !IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
 Style.isCpp() && !IsCpp11AttributeSpecifier &&
-Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
+!IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression &&
+Left->isNot(TT_LambdaLSquare) &&
 !CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
 (!Parent ||
  Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
@@ -496,7 +497,7 @@
   } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
  Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
 Left->Type = TT_DesignatedInitializerLSquare;
-  } else if (IsCSharp11AttributeSpecifier) {
+  } else if (IsCSharpAttributeSpecifier) {
 Left->Type = TT_AttributeSquare;
   } else if (CurrentToken->is(tok::r_square) && Parent &&
  Parent->is(TT_TemplateCloser)) {
@@ -559,13 +560,13 @@
 
 Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr;
 Contexts.back().InCpp11AttributeSpecifier = IsCpp11AttributeSpecifier;
-Contexts.back().InCSharpAttributeSpecifier = IsCSharp11AttributeSpecifier;
+Contexts.back().InCSharpAttributeSpecifier = IsCSharpAttributeSpecifier;
 
 while (CurrentToken) {
   if (CurrentToken->is(tok::r_square)) {
 if (IsCpp11AttributeSpecifier)
   CurrentToken->Type = TT_AttributeSquare;
-if (IsCSharp11AttributeSpecifier)
+if (IsCSharpAttributeSpecifier)
   CurrentToken->Type = TT_AttributeSquare;
 else if (((CurrentToken->Next &&
CurrentToken->Next->is(tok::l_paren)) ||
@@ -777,6 +778,10 @@
   break;
 }
   } else if (Style.isCSharp()) {
+if (Contexts.back().InCSharpAttributeSpecifier) {
+  Tok->Type = TT_AttributeColon;
+  break;
+}
 if (Contexts.back().ContextKind == tok::l_paren) {
   Tok->Type = TT_CSharpNamedArgumentColon;
   break;
@@ -3550,8 +3555,8 @@
   const FormatToken &Left = *Right.Previous;
   // Language-specific stuff.
   if (Style.isCSharp()) {
-if (Left.is(TT_CSharpNamedArgumentColon) ||
-Right.is(TT_CSharpNamedArgumentColon))
+if (Left.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon) ||
+Right.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon))
   return false;
   } else if (Style.Language == FormatStyle::LK_Java) {
 if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
Index: clang/lib/Format/FormatTokenLexer.h
===
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -55,7 +55,6 @@
   bool tryMergeCSharpDoubleQuestion();
   bool tryMergeCSharpNullConditional();
   bool tryTransformCSharpForEach();
-  bool tryMergeCSharpAttributeAndTarget();
 
   bool tryMerge

[PATCH] D75456: [clang-format] Rename CSharpNullConditionalSq and add missing test

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 247643.

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

https://reviews.llvm.org/D75456

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -607,6 +607,7 @@
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
+  verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -972,7 +972,7 @@
   }
   break;
 case tok::question:
-  if (Tok->is(TT_CSharpNullConditionalSq)) {
+  if (Tok->is(TT_CSharpNullConditionalLSquare)) {
 if (!parseSquare())
   return false;
 break;
@@ -1456,7 +1456,7 @@
 return;
   }
   if (CurrentToken->TokenText == "?[") {
-Current.Type = TT_CSharpNullConditionalSq;
+Current.Type = TT_CSharpNullConditionalLSquare;
 return;
   }
 }
@@ -2947,11 +2947,11 @@
   return true;
 
 // No space before '?['.
-if (Right.is(TT_CSharpNullConditionalSq))
+if (Right.is(TT_CSharpNullConditionalLSquare))
   return false;
 
 // Possible space inside `?[ 0 ]`.
-if (Left.is(TT_CSharpNullConditionalSq))
+if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;
 
 // space between keywords and paren e.g. "using ("
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -345,7 +345,7 @@
 
   if (PeriodOrLSquare->is(tok::l_square)) {
 Question->Tok.setKind(tok::question); // no '?[' in clang tokens.
-Question->Type = TT_CSharpNullConditionalSq;
+Question->Type = TT_CSharpNullConditionalLSquare;
   } else {
 Question->Tok.setKind(tok::question); // no '?.' in clang tokens.
 Question->Type = TT_CSharpNullConditional;
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -106,7 +106,7 @@
   TYPE(CSharpNullable) 
\
   TYPE(CSharpNullCoalescing)   
\
   TYPE(CSharpNullConditional)  
\
-  TYPE(CSharpNullConditionalSq)
\
+  TYPE(CSharpNullConditionalLSquare)   
\
   TYPE(Unknown)
 
 enum TokenType {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -607,6 +607,7 @@
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
+  verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -972,7 +972,7 @@
   }
   break;
 case tok::question:
-  if (Tok->is(TT_CSharpNullConditionalSq)) {
+  if (Tok->is(TT_CSharpNullConditionalLSquare)) {
 if (!parseSquare())
   return false;
 break;
@@ -1456,7 +1456,7 @@
 return;
   }
   if (CurrentToken->TokenText == "?[") {
-Current.Type = TT_CSharpNullConditionalSq;
+Current.Type = TT_CSharpNullConditionalLSquare;
 return;
   }
 }
@@ -2947,11 +2947,11 @@
   return true;
 
 // No space before '?['.
-if (Right.is(TT_CSharpNullConditionalSq))
+if (Right.is(TT_CSharpNullConditionalLSquare))
   return false;
 
 // Possible space inside `?[ 0 ]`.
-if (Left.is(TT_CSharpNullConditionalSq))
+if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;
 
 // space between keywords and paren e.g. "using ("
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -345,7 +345,7 @@
 
   if (PeriodOrLSquare->is(tok::l_square)) {
 Question->Tok.setKind(tok::question); // no '?[' in clang tokens.
-Question->Type = TT_

[PATCH] D75456: [clang-format] Rename CSharpNullConditionalSq and add missing test

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Rename CSharpNullConditionalSq to CSharpNullConditionalLSquare.

Add test for spaces inside [] with C# Null conditionals.

Address comments missed from https://reviews.llvm.org/D75368.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75456

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -607,6 +607,7 @@
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
+  verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -972,7 +972,7 @@
   }
   break;
 case tok::question:
-  if (Tok->is(TT_CSharpNullConditionalSq)) {
+  if (Tok->is(TT_CSharpNullConditionalLSquare)) {
 if (!parseSquare())
   return false;
 break;
@@ -1456,7 +1456,7 @@
 return;
   }
   if (CurrentToken->TokenText == "?[") {
-Current.Type = TT_CSharpNullConditionalSq;
+Current.Type = TT_CSharpNullConditionalLSquare;
 return;
   }
 }
@@ -2947,11 +2947,11 @@
   return true;
 
 // No space before '?['.
-if (Right.is(TT_CSharpNullConditionalSq))
+if (Right.is(TT_CSharpNullConditionalLSquare))
   return false;
 
 // Possible space inside `?[ 0 ]`.
-if (Left.is(TT_CSharpNullConditionalSq))
+if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;
 
 // space between keywords and paren e.g. "using ("
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -345,7 +345,7 @@
 
   if (PeriodOrLSquare->is(tok::l_square)) {
 Question->Tok.setKind(tok::question); // no '?[' in clang tokens.
-Question->Type = TT_CSharpNullConditionalSq;
+Question->Type = TT_CSharpNullConditionalLSquare;
   } else {
 Question->Tok.setKind(tok::question); // no '?.' in clang tokens.
 Question->Type = TT_CSharpNullConditional;
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -106,7 +106,7 @@
   TYPE(CSharpNullable) 
\
   TYPE(CSharpNullCoalescing)   
\
   TYPE(CSharpNullConditional)  
\
-  TYPE(CSharpNullConditionalSq)
\
+  TYPE(CSharpNullConditionalLSquare)   
 \
   TYPE(Unknown)
 
 enum TokenType {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -607,6 +607,7 @@
 
   Style.SpacesInSquareBrackets = true;
   verifyFormat(R"(private float[ , ] Values;)", Style);
+  verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -972,7 +972,7 @@
   }
   break;
 case tok::question:
-  if (Tok->is(TT_CSharpNullConditionalSq)) {
+  if (Tok->is(TT_CSharpNullConditionalLSquare)) {
 if (!parseSquare())
   return false;
 break;
@@ -1456,7 +1456,7 @@
 return;
   }
   if (CurrentToken->TokenText == "?[") {
-Current.Type = TT_CSharpNullConditionalSq;
+Current.Type = TT_CSharpNullConditionalLSquare;
 return;
   }
 }
@@ -2947,11 +2947,11 @@
   return true;
 
 // No space before '?['.
-if (Right.is(TT_CSharpNullConditionalSq))
+if (Right.is(TT_CSharpNullConditionalLSquare))
   return false;
 
 // Possible space inside `?[ 0 ]`.
-if (Left.is(TT_CSharpNullConditionalSq))
+if (Left.is(TT_CSharpNullConditionalLSquare))
   return Style.SpacesInSquareBrackets;
 
 // space between keywords and paren e.g. "using ("
Index: clang/lib/Format/FormatTokenLexer.cpp
===

[PATCH] D75455: [clang-format] Allow nested [] in C# attributes

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Keep track of unpaired [] when identifying C# attribute lines


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75455

Files:
  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
@@ -273,6 +273,15 @@
"{\n"
"}");
 
+  // [] in an attribute do not cause premature line wrapping or indenting.
+  verifyFormat(R"(//
+public class A
+{
+[SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)]
+[DoNotSerialize]
+public Data MemberVariable;
+})");
+
   //  Unwrappable lines go on a line of their own.
   // 'target:' is not treated as a label.
   // Modify Style to enforce a column limit.
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -324,12 +324,21 @@
 }
 
 void UnwrappedLineParser::parseCSharpAttribute() {
+  int UnpairedSquareBrackets = 1;
   do {
 switch (FormatTok->Tok.getKind()) {
 case tok::r_square:
   nextToken();
-  addUnwrappedLine();
-  return;
+  --UnpairedSquareBrackets;
+  if (UnpairedSquareBrackets == 0) {
+addUnwrappedLine();
+return;
+  }
+  break;
+case tok::l_square:
+  ++UnpairedSquareBrackets;
+  nextToken();
+  break;
 default:
   nextToken();
   break;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -273,6 +273,15 @@
"{\n"
"}");
 
+  // [] in an attribute do not cause premature line wrapping or indenting.
+  verifyFormat(R"(//
+public class A
+{
+[SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)]
+[DoNotSerialize]
+public Data MemberVariable;
+})");
+
   //  Unwrappable lines go on a line of their own.
   // 'target:' is not treated as a label.
   // Modify Style to enforce a column limit.
Index: clang/lib/Format/UnwrappedLineParser.cpp
===
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -324,12 +324,21 @@
 }
 
 void UnwrappedLineParser::parseCSharpAttribute() {
+  int UnpairedSquareBrackets = 1;
   do {
 switch (FormatTok->Tok.getKind()) {
 case tok::r_square:
   nextToken();
-  addUnwrappedLine();
-  return;
+  --UnpairedSquareBrackets;
+  if (UnpairedSquareBrackets == 0) {
+addUnwrappedLine();
+return;
+  }
+  break;
+case tok::l_square:
+  ++UnpairedSquareBrackets;
+  nextToken();
+  break;
 default:
   nextToken();
   break;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75368: [clang-format] Handle NullCoalescing and NullConditional operators in C#

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 247610.
jbcoe edited the summary of this revision.
jbcoe added a comment.

Do not add new punctuators for ??, ?. and ?[


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

https://reviews.llvm.org/D75368

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

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -170,6 +170,12 @@
   verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
 }
 
+TEST_F(FormatTestCSharp, CSharpConditionalExpressions) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  // conditional expression is not seen as a NullConditional.
+  verifyFormat("var y = A < B ? -1 : 1;", Style);
+}
+
 TEST_F(FormatTestCSharp, CSharpNullConditional) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -972,6 +972,13 @@
   }
   break;
 case tok::question:
+  if (Tok->is(TT_CSharpNullConditionalSq)) {
+if (!parseSquare())
+  return false;
+break;
+  }
+  if (Tok->isOneOf(TT_CSharpNullConditional, TT_CSharpNullCoalescing))
+break;
   if (Style.Language == FormatStyle::LK_JavaScript && Tok->Next &&
   Tok->Next->isOneOf(tok::semi, tok::comma, tok::colon, tok::r_paren,
  tok::r_brace)) {
@@ -987,9 +994,11 @@
   if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
   Style.Language == FormatStyle::LK_JavaScript)
 break;
-  if (Style.isCSharp() && Line.MustBeDeclaration) {
-Tok->Type = TT_CSharpNullableTypeQuestionMark;
-break;
+  if (Style.isCSharp()) {
+if (Line.MustBeDeclaration && !Contexts.back().IsExpression) {
+  Tok->Type = TT_CSharpNullable;
+  break;
+}
   }
   parseConditional();
   break;
@@ -1437,6 +1446,21 @@
   // The token type is already known.
   return;
 
+if (Style.isCSharp() && CurrentToken->is(tok::question)) {
+  if (CurrentToken->TokenText == "??") {
+Current.Type = TT_CSharpNullCoalescing;
+return;
+  }
+  if (CurrentToken->TokenText == "?.") {
+Current.Type = TT_CSharpNullConditional;
+return;
+  }
+  if (CurrentToken->TokenText == "?[") {
+Current.Type = TT_CSharpNullConditionalSq;
+return;
+  }
+}
+
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
@@ -2907,9 +2931,29 @@
   return Style.SpacesInSquareBrackets;
 
 // No space before ? in nullable types.
-if (Right.is(TT_CSharpNullableTypeQuestionMark))
+if (Right.is(TT_CSharpNullable))
+  return false;
+
+// Require space after ? in nullable types.
+if (Left.is(TT_CSharpNullable))
+  return true;
+
+// No space before or after '?.'.
+if (Left.is(TT_CSharpNullConditional) || Right.is(TT_CSharpNullConditional))
   return false;
 
+// Space before and after '??'.
+if (Left.is(TT_CSharpNullCoalescing) || Right.is(TT_CSharpNullCoalescing))
+  return true;
+
+// No space before '?['.
+if (Right.is(TT_CSharpNullConditionalSq))
+  return false;
+
+// Possible space inside `?[ 0 ]`.
+if (Left.is(TT_CSharpNullConditionalSq))
+  return Style.SpacesInSquareBrackets;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
Index: clang/lib/Format/FormatTokenLexer.h
===
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -52,8 +52,8 @@
   bool tryMergeJSPrivateIdentifier();
   bool tryMergeCSharpStringLiteral();
   bool tryMergeCSharpKeywordVariables();
-  bool tryMergeCSharpNullConditionals();
   bool tryMergeCSharpDoubleQuestion();
+  bool tryMergeCSharpNullConditional();
   bool tryTransformCSharpForEach();
   bool tryMergeCSharpAttributeAndTarget();
 
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -84,7 +84,7 @@
   return;
 if (tryMergeCSharpDoubleQuestion())
   return;
-if (tryMergeCSharpNullConditionals())
+if (tryMergeCSharpNullConditional())
   return;
 if (tryTransformCShar

[PATCH] D75368: [clang-format] Handle ?. ?? and ?[ as C# tokens

2020-03-02 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe planned changes to this revision.
jbcoe added a comment.

Handle ??, ?. and ?[ in lib/Format/FormatTokenLexer.


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

https://reviews.llvm.org/D75368



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


[PATCH] D75368: [clang-format] Handle ?. ?? and ?[ as C# tokens

2020-02-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 247399.
jbcoe added a comment.

Fix failing test by parsing tokens after '?[' in the same way as tokens after 
'['.


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

https://reviews.llvm.org/D75368

Files:
  clang/include/clang/Basic/TokenKinds.def
  clang/lib/Format/FormatToken.h
  clang/lib/Format/FormatTokenLexer.cpp
  clang/lib/Format/FormatTokenLexer.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestCSharp.cpp

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -170,6 +170,12 @@
   verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
 }
 
+TEST_F(FormatTestCSharp, CSharpConditionalExpressions) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  // conditional expression is not seen as a NullConditional.
+  verifyFormat("var y = A < B ? -1 : 1;", Style);
+}
+
 TEST_F(FormatTestCSharp, CSharpNullConditional) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -902,6 +902,7 @@
 Line.MightBeFunctionDecl = true;
   break;
 case tok::l_square:
+case tok::questionlsquare:
   if (!parseSquare())
 return false;
   break;
@@ -987,9 +988,11 @@
   if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
   Style.Language == FormatStyle::LK_JavaScript)
 break;
-  if (Style.isCSharp() && Line.MustBeDeclaration) {
-Tok->Type = TT_CSharpNullableTypeQuestionMark;
-break;
+  if (Style.isCSharp()) {
+if (Line.MustBeDeclaration && !Contexts.back().IsExpression) {
+  Tok->Type = TT_CSharpNullable;
+  break;
+}
   }
   parseConditional();
   break;
@@ -1437,6 +1440,21 @@
   // The token type is already known.
   return;
 
+if (Style.isCSharp()) {
+  if (CurrentToken->is(tok::questionquestion)) {
+Current.Type = TT_CSharpNullCoalescing;
+return;
+  }
+  if (CurrentToken->is(tok::questionperiod)) {
+Current.Type = TT_CSharpNullConditional;
+return;
+  }
+  if (CurrentToken->is(tok::questionlsquare)) {
+Current.Type = TT_CSharpNullConditionalSq;
+return;
+  }
+}
+
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
@@ -2907,9 +2925,29 @@
   return Style.SpacesInSquareBrackets;
 
 // No space before ? in nullable types.
-if (Right.is(TT_CSharpNullableTypeQuestionMark))
+if (Right.is(TT_CSharpNullable))
+  return false;
+
+// Require space after ? in nullable types.
+if (Left.is(TT_CSharpNullable))
+  return true;
+
+// No space before or after '?.'.
+if (Left.is(TT_CSharpNullConditional) || Right.is(TT_CSharpNullConditional))
   return false;
 
+// Space before and after '??'.
+if (Left.is(TT_CSharpNullCoalescing) || Right.is(TT_CSharpNullCoalescing))
+  return true;
+
+// No space before '?['.
+if (Right.is(TT_CSharpNullConditionalSq))
+  return false;
+
+// Possible space inside `?[ 0 ]`.
+if (Left.is(TT_CSharpNullConditionalSq))
+  return Style.SpacesInSquareBrackets;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
Index: clang/lib/Format/FormatTokenLexer.h
===
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -52,8 +52,8 @@
   bool tryMergeJSPrivateIdentifier();
   bool tryMergeCSharpStringLiteral();
   bool tryMergeCSharpKeywordVariables();
-  bool tryMergeCSharpNullConditionals();
   bool tryMergeCSharpDoubleQuestion();
+  bool tryMergeCSharpNullConditional();
   bool tryTransformCSharpForEach();
   bool tryMergeCSharpAttributeAndTarget();
 
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -84,7 +84,7 @@
   return;
 if (tryMergeCSharpDoubleQuestion())
   return;
-if (tryMergeCSharpNullConditionals())
+if (tryMergeCSharpNullConditional())
   return;
 if (tryTransformCSharpForEach())
   return;
@@ -319,7 +319,7 @@
   auto &SecondQuestion = *(Tokens.end() - 1);
   if (!FirstQuestion->is(tok::question) || !SecondQuestion->is(tok::question))
 return false;
-  FirstQuestion->Tok.setKind(tok::question);
+  FirstQuestion->Tok.setKi

[PATCH] D75368: [clang-format] Handle ?. ?? and ?[ as C# tokens

2020-02-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe planned changes to this revision.
jbcoe added a comment.

There's a weird test failure I'm unable to reproduce outside of the tests with 
real source code where

  public static void Main(string[] args)
  { 
string dirPath = args?[0];
  }

is (mis)-formatted as

  public static void Main(string[] args)
  { string dirPath = args?[0];
  }


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75368



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


[PATCH] D75368: [clang-format] Handle ?. ?? and ?[ as C# tokens

2020-02-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
jbcoe planned changes to this revision.
jbcoe added a comment.

There's a weird test failure I'm unable to reproduce outside of the tests with 
real source code where

  public static void Main(string[] args)
  { 
string dirPath = args?[0];
  }

is (mis)-formatted as

  public static void Main(string[] args)
  { string dirPath = args?[0];
  }


Disable merging of Type? into a single token.

Introduce ??, ?. and ?[ as new punctuators.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75368

Files:
  clang/include/clang/Basic/TokenKinds.def
  clang/lib/Format/FormatToken.h
  clang/lib/Format/FormatTokenLexer.cpp
  clang/lib/Format/FormatTokenLexer.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestCSharp.cpp

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -170,6 +170,12 @@
   verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
 }
 
+TEST_F(FormatTestCSharp, CSharpConditionalExpressions) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  // conditional expression is not seen as a NullConditional.
+  verifyFormat("var y = A < B ? -1 : 1;", Style);
+}
+
 TEST_F(FormatTestCSharp, CSharpNullConditional) {
   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -987,9 +987,11 @@
   if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
   Style.Language == FormatStyle::LK_JavaScript)
 break;
-  if (Style.isCSharp() && Line.MustBeDeclaration) {
-Tok->Type = TT_CSharpNullableTypeQuestionMark;
-break;
+  if (Style.isCSharp()) {
+if (Line.MustBeDeclaration && !Contexts.back().IsExpression) {
+  Tok->Type = TT_CSharpNullable;
+  break;
+}
   }
   parseConditional();
   break;
@@ -1437,6 +1439,21 @@
   // The token type is already known.
   return;
 
+if (Style.isCSharp()) {
+  if (CurrentToken->is(tok::questionquestion)) {
+Current.Type = TT_CSharpNullCoalescing;
+return;
+  }
+  if (CurrentToken->is(tok::questionperiod)) {
+Current.Type = TT_CSharpNullConditional;
+return;
+  }
+  if (CurrentToken->is(tok::questionlsquare)) {
+Current.Type = TT_CSharpNullConditionalSq;
+return;
+  }
+}
+
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
@@ -2907,9 +2924,25 @@
   return Style.SpacesInSquareBrackets;
 
 // No space before ? in nullable types.
-if (Right.is(TT_CSharpNullableTypeQuestionMark))
+if (Right.is(TT_CSharpNullable))
   return false;
 
+// Require space after ? in nullable types.
+if (Left.is(TT_CSharpNullable))
+  return true;
+
+// No space before or after '?.'.
+if (Left.is(TT_CSharpNullConditional) || Right.is(TT_CSharpNullConditional))
+  return false;
+
+// Space before and after '??'.
+if (Left.is(TT_CSharpNullCoalescing) || Right.is(TT_CSharpNullCoalescing))
+  return true;
+
+// Possible space inside `?[ 0 ]`.
+if (Left.is(TT_CSharpNullConditionalSq))
+  return Style.SpacesInSquareBrackets;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
Index: clang/lib/Format/FormatTokenLexer.h
===
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -52,8 +52,8 @@
   bool tryMergeJSPrivateIdentifier();
   bool tryMergeCSharpStringLiteral();
   bool tryMergeCSharpKeywordVariables();
-  bool tryMergeCSharpNullConditionals();
   bool tryMergeCSharpDoubleQuestion();
+  bool tryMergeCSharpNullConditional();
   bool tryTransformCSharpForEach();
   bool tryMergeCSharpAttributeAndTarget();
 
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -84,7 +84,7 @@
   return;
 if (tryMergeCSharpDoubleQuestion())
   return;
-if (tryMergeCSharpNullConditionals())
+if (tryMergeCSharpNullConditional())
   return;
 if (tryTransformCSharpForEach())
   return;
@@ -319,7 +319,7 @@
   auto &SecondQuestion = *(Tokens.end() - 1);
   if (!FirstQuestion->is(tok::ques

[PATCH] D75194: [clang-format] Do not merge very long C# automatic properties

2020-02-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked an inline comment as done.
jbcoe added inline comments.



Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:489
+// If the Limit is broken, split the default value onto a new line and
+// indent it.
+//

krasimir wrote:
> Why not always (not just when Limit is broken) merge the whole automatic 
> property declaration into 1 line?
> Syntactically, this whole thing is a unit:
> `MyVeryLongTypeName Name { get; set } = new MyVeryLongTypeName();`
> My C# is rusty, what are the things after the `=` that are syntactically 
> allowed in general?
I think any expression is valid.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75194



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


[PATCH] D75336: [clang-format] Improve C# handling of spaces in square brackets

2020-02-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added reviewers: MyDeveloperDay, krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75336

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -600,7 +600,7 @@
   verifyFormat(R"(private float[,] Values;)", Style);
 
   Style.SpacesInSquareBrackets = true;
-  verifyFormat(R"(private float[, ] Values;)", Style);
+  verifyFormat(R"(private float[ , ] Values;)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
@@ -608,11 +608,7 @@
   Style.SpacesInSquareBrackets = false;
 
   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
-
-  // Erroneous spaces in square brackets here will be tackled in a follow-up
-  // patch and are not addressed by setting
-  // `Style.SpacesInSquareBrackets = false;`
-  verifyFormat(R"(int?[] arr = new int?[ 10 ];)",
+  verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
 }
 
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2902,8 +2902,8 @@
 if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
   return true;
 
-// space after comma in '[,]'.
-if (Left.is(tok::comma) && Right.is(tok::r_square))
+// spaces inside square brackets.
+if (Left.is(tok::l_square) || Right.is(tok::r_square))
   return Style.SpacesInSquareBrackets;
 
 // No space before ? in nullable types.


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -600,7 +600,7 @@
   verifyFormat(R"(private float[,] Values;)", Style);
 
   Style.SpacesInSquareBrackets = true;
-  verifyFormat(R"(private float[, ] Values;)", Style);
+  verifyFormat(R"(private float[ , ] Values;)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
@@ -608,11 +608,7 @@
   Style.SpacesInSquareBrackets = false;
 
   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
-
-  // Erroneous spaces in square brackets here will be tackled in a follow-up
-  // patch and are not addressed by setting
-  // `Style.SpacesInSquareBrackets = false;`
-  verifyFormat(R"(int?[] arr = new int?[ 10 ];)",
+  verifyFormat(R"(int?[] arr = new int?[10];)",
Style); // An array of a nullable type.
 }
 
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2902,8 +2902,8 @@
 if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
   return true;
 
-// space after comma in '[,]'.
-if (Left.is(tok::comma) && Right.is(tok::r_square))
+// spaces inside square brackets.
+if (Left.is(tok::l_square) || Right.is(tok::r_square))
   return Style.SpacesInSquareBrackets;
 
 // No space before ? in nullable types.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75261: [clang-format] Recognize C# nullable types

2020-02-28 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 247193.
jbcoe added a comment.

Add additional test following review discussion


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

https://reviews.llvm.org/D75261

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -175,7 +175,7 @@
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
 
   verifyFormat(
-  "public Person(string firstName, string lastName, int? age=null)");
+  "public Person(string firstName, string lastName, int? age = null)");
 
   verifyFormat("foo () {\n"
"  switch (args?.Length) {}\n"
@@ -603,5 +603,18 @@
   verifyFormat(R"(private float[, ] Values;)", Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpNullableTypes) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  Style.SpacesInSquareBrackets = false;
+
+  verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+
+  // Erroneous spaces in square brackets here will be tackled in a follow-up
+  // patch and are not addressed by setting
+  // `Style.SpacesInSquareBrackets = false;`
+  verifyFormat(R"(int?[] arr = new int?[ 10 ];)",
+   Style); // An array of a nullable type.
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -987,6 +987,10 @@
   if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
   Style.Language == FormatStyle::LK_JavaScript)
 break;
+  if (Style.isCSharp() && Line.MustBeDeclaration) {
+Tok->Type = TT_CSharpNullableTypeQuestionMark;
+break;
+  }
   parseConditional();
   break;
 case tok::kw_template:
@@ -2902,6 +2906,10 @@
 if (Left.is(tok::comma) && Right.is(tok::r_square))
   return Style.SpacesInSquareBrackets;
 
+// No space before ? in nullable types.
+if (Right.is(TT_CSharpNullableTypeQuestionMark))
+  return false;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -104,6 +104,7 @@
   TYPE(CSharpStringLiteral)
\
   TYPE(CSharpNullCoalescing)   
\
   TYPE(CSharpNamedArgumentColon)   
\
+  TYPE(CSharpNullableTypeQuestionMark) 
\
   TYPE(Unknown)
 
 enum TokenType {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -175,7 +175,7 @@
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
 
   verifyFormat(
-  "public Person(string firstName, string lastName, int? age=null)");
+  "public Person(string firstName, string lastName, int? age = null)");
 
   verifyFormat("foo () {\n"
"  switch (args?.Length) {}\n"
@@ -603,5 +603,18 @@
   verifyFormat(R"(private float[, ] Values;)", Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpNullableTypes) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  Style.SpacesInSquareBrackets = false;
+
+  verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+
+  // Erroneous spaces in square brackets here will be tackled in a follow-up
+  // patch and are not addressed by setting
+  // `Style.SpacesInSquareBrackets = false;`
+  verifyFormat(R"(int?[] arr = new int?[ 10 ];)",
+   Style); // An array of a nullable type.
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -987,6 +987,10 @@
   if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
   Style.Language == FormatStyle::LK_JavaScript)
 break;
+  if (Style.isCSharp() && Line.MustBeDeclaration) {
+Tok->Type = TT_CSharpNullableTypeQuestionMark;
+break;
+  }
   parseConditional();
   break;
 case tok::kw_template:
@@ -2902,6 +2906,10 @@
 if (Left.is(tok::comma) && Right.is(tok::r_square))
   return Style.SpacesInSquareBrackets;
 
+// No space before ? in nullable types.
+if (Right

[PATCH] D75261: [clang-format] Recognize C# nullable types

2020-02-27 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked an inline comment as done.
jbcoe added inline comments.



Comment at: clang/unittests/Format/FormatTestCSharp.cpp:178
   verifyFormat(
-  "public Person(string firstName, string lastName, int? age=null)");
+  "public Person(string firstName, string lastName, int? age = null)");
 

This will be formatted as 

public Person(string firstName, string lastName, int age = null);

without the Nullable Type.



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D75261



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


[PATCH] D75261: [clang-format] Recognize C# nullable types

2020-02-27 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Do not confuse C# nullable types with conditional expressions.

Do not put a space before the `?` in `[access-modifier] Type? variableName;`


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75261

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -175,7 +175,7 @@
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
 
   verifyFormat(
-  "public Person(string firstName, string lastName, int? age=null)");
+  "public Person(string firstName, string lastName, int? age = null)");
 
   verifyFormat("foo () {\n"
"  switch (args?.Length) {}\n"
@@ -603,5 +603,11 @@
   verifyFormat(R"(private float[, ] Values;)", Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpNullableTypes) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -987,6 +987,10 @@
   if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
   Style.Language == FormatStyle::LK_JavaScript)
 break;
+  if (Style.isCSharp() && Line.MustBeDeclaration) {
+Tok->Type = TT_CSharpNullableTypeQuestionMark;
+break;
+  }
   parseConditional();
   break;
 case tok::kw_template:
@@ -2902,6 +2906,10 @@
 if (Left.is(tok::comma) && Right.is(tok::r_square))
   return Style.SpacesInSquareBrackets;
 
+// No space before ? in nullable types.
+if (Right.is(TT_CSharpNullableTypeQuestionMark))
+  return false;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -104,6 +104,7 @@
   TYPE(CSharpStringLiteral)
\
   TYPE(CSharpNullCoalescing)   
\
   TYPE(CSharpNamedArgumentColon)   
\
+  TYPE(CSharpNullableTypeQuestionMark) 
\
   TYPE(Unknown)
 
 enum TokenType {


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -175,7 +175,7 @@
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
 
   verifyFormat(
-  "public Person(string firstName, string lastName, int? age=null)");
+  "public Person(string firstName, string lastName, int? age = null)");
 
   verifyFormat("foo () {\n"
"  switch (args?.Length) {}\n"
@@ -603,5 +603,11 @@
   verifyFormat(R"(private float[, ] Values;)", Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpNullableTypes) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -987,6 +987,10 @@
   if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
   Style.Language == FormatStyle::LK_JavaScript)
 break;
+  if (Style.isCSharp() && Line.MustBeDeclaration) {
+Tok->Type = TT_CSharpNullableTypeQuestionMark;
+break;
+  }
   parseConditional();
   break;
 case tok::kw_template:
@@ -2902,6 +2906,10 @@
 if (Left.is(tok::comma) && Right.is(tok::r_square))
   return Style.SpacesInSquareBrackets;
 
+// No space before ? in nullable types.
+if (Right.is(TT_CSharpNullableTypeQuestionMark))
+  return false;
+
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -104,6 +104,7 @@
   TYPE(CSharpStringLiteral)   

[PATCH] D75244: [clang-format] Recognize C# named argument colons as a token type

2020-02-27 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 246924.
jbcoe added a comment.

Consolidate if blocks following review comment.


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

https://reviews.llvm.org/D75244

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

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -546,6 +546,8 @@
 PrintOrderDetails(orderNum: 31, productName: "Red Mug",  // comment
   sellerName: "Gift Shop");)",
Style);
+
+  verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -776,6 +776,11 @@
   Tok->Type = TT_JsTypeColon;
   break;
 }
+  } else if (Style.isCSharp()) {
+if (Contexts.back().ContextKind == tok::l_paren) {
+  Tok->Type = TT_CSharpNamedArgumentColon;
+  break;
+}
   }
   if (Contexts.back().ColonIsDictLiteral ||
   Style.Language == FormatStyle::LK_Proto ||
@@ -3052,6 +3057,8 @@
   return Style.SpacesInContainerLiterals;
 if (Right.is(TT_AttributeColon))
   return false;
+if (Right.is(TT_CSharpNamedArgumentColon))
+  return false;
 return true;
   }
   if (Left.is(TT_UnaryOperator)) {
@@ -3200,7 +3207,11 @@
   if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0)
 return true;
 
-  if (Style.Language == FormatStyle::LK_JavaScript) {
+  if (Style.isCSharp()) {
+if (Right.is(TT_CSharpNamedArgumentColon) ||
+Left.is(TT_CSharpNamedArgumentColon))
+  return false;
+  } else if (Style.Language == FormatStyle::LK_JavaScript) {
 // FIXME: This might apply to other languages and token kinds.
 if (Right.is(tok::string_literal) && Left.is(tok::plus) && Left.Previous &&
 Left.Previous->is(tok::string_literal))
@@ -3485,9 +3496,12 @@
 bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
 const FormatToken &Right) {
   const FormatToken &Left = *Right.Previous;
-
   // Language-specific stuff.
-  if (Style.Language == FormatStyle::LK_Java) {
+  if (Style.isCSharp()) {
+if (Left.is(TT_CSharpNamedArgumentColon) ||
+Right.is(TT_CSharpNamedArgumentColon))
+  return false;
+  } else if (Style.Language == FormatStyle::LK_Java) {
 if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
  Keywords.kw_implements))
   return false;
Index: clang/lib/Format/FormatTokenLexer.h
===
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -56,7 +56,6 @@
   bool tryMergeCSharpDoubleQuestion();
   bool tryTransformCSharpForEach();
   bool tryMergeCSharpAttributeAndTarget();
-  bool tryMergeCSharpNamedArgument();
 
   bool tryMergeTokens(ArrayRef Kinds, TokenType NewType);
 
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -76,8 +76,6 @@
 return;
 
   if (Style.isCSharp()) {
-if (tryMergeCSharpNamedArgument())
-  return;
 if (tryMergeCSharpAttributeAndTarget())
   return;
 if (tryMergeCSharpKeywordVariables())
@@ -186,39 +184,6 @@
   return true;
 }
 
-// Merge 'argName' and ':' into a single token in `foo(argName: bar)`.
-bool FormatTokenLexer::tryMergeCSharpNamedArgument() {
-  if (Tokens.size() < 2)
-return false;
-  auto &Colon = *(Tokens.end() - 1);
-  if (!Colon->is(tok::colon))
-return false;
-
-  auto &Name = *(Tokens.end() - 2);
-  if (!Name->is(tok::identifier))
-return false;
-
-  const FormatToken *CommaOrLeftParen = nullptr;
-  for (auto I = Tokens.rbegin() + 2, E = Tokens.rend(); I != E; ++I) {
-// NB: Because previous pointers are not initialized yet, this cannot use
-// Token.getPreviousNonComment.
-if ((*I)->isNot(tok::comment)) {
-  CommaOrLeftParen = *I;
-  break;
-}
-  }
-
-  if (!CommaOrLeftParen || !CommaOrLeftParen->isOneOf(tok::l_paren, tok::comma))
-return false;
-
-  Name->TokenText = StringRef(Name->TokenText.begin(),
-  Colon->TokenText.end() - Name->TokenText.begin());
-  Name->ColumnWidth += Colon->ColumnWidth;
-  Name->Type = TT_CSharpNamedArgument;
-  Tokens.erase(Tokens.end() - 1);
-  return true;
-}
-
 // Search for verbatim or interpolated string literals @"ABC" or
 // $"a{abc}a" i a

[PATCH] D75244: [clang-format] Recognize C# named argument colons as a token type

2020-02-27 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: krasimir.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

No longer merge 'name' and ':' into a single token.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75244

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

Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -546,6 +546,8 @@
 PrintOrderDetails(orderNum: 31, productName: "Red Mug",  // comment
   sellerName: "Gift Shop");)",
Style);
+
+  verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -776,6 +776,11 @@
   Tok->Type = TT_JsTypeColon;
   break;
 }
+  } else if (Style.isCSharp()) {
+if (Contexts.back().ContextKind == tok::l_paren) {
+  Tok->Type = TT_CSharpNamedArgumentColon;
+  break;
+}
   }
   if (Contexts.back().ColonIsDictLiteral ||
   Style.Language == FormatStyle::LK_Proto ||
@@ -3052,6 +3057,8 @@
   return Style.SpacesInContainerLiterals;
 if (Right.is(TT_AttributeColon))
   return false;
+if (Right.is(TT_CSharpNamedArgumentColon))
+  return false;
 return true;
   }
   if (Left.is(TT_UnaryOperator)) {
@@ -3200,7 +3207,11 @@
   if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0)
 return true;
 
-  if (Style.Language == FormatStyle::LK_JavaScript) {
+  if (Style.isCSharp()) {
+if (Right.is(TT_CSharpNamedArgumentColon) ||
+Left.is(TT_CSharpNamedArgumentColon))
+  return false;
+  } else if (Style.Language == FormatStyle::LK_JavaScript) {
 // FIXME: This might apply to other languages and token kinds.
 if (Right.is(tok::string_literal) && Left.is(tok::plus) && Left.Previous &&
 Left.Previous->is(tok::string_literal))
@@ -3485,7 +3496,11 @@
 bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
 const FormatToken &Right) {
   const FormatToken &Left = *Right.Previous;
-
+  if (Style.isCSharp()) {
+if (Left.is(TT_CSharpNamedArgumentColon) ||
+Right.is(TT_CSharpNamedArgumentColon))
+  return false;
+  }
   // Language-specific stuff.
   if (Style.Language == FormatStyle::LK_Java) {
 if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
Index: clang/lib/Format/FormatTokenLexer.h
===
--- clang/lib/Format/FormatTokenLexer.h
+++ clang/lib/Format/FormatTokenLexer.h
@@ -56,7 +56,6 @@
   bool tryMergeCSharpDoubleQuestion();
   bool tryTransformCSharpForEach();
   bool tryMergeCSharpAttributeAndTarget();
-  bool tryMergeCSharpNamedArgument();
 
   bool tryMergeTokens(ArrayRef Kinds, TokenType NewType);
 
Index: clang/lib/Format/FormatTokenLexer.cpp
===
--- clang/lib/Format/FormatTokenLexer.cpp
+++ clang/lib/Format/FormatTokenLexer.cpp
@@ -76,8 +76,6 @@
 return;
 
   if (Style.isCSharp()) {
-if (tryMergeCSharpNamedArgument())
-  return;
 if (tryMergeCSharpAttributeAndTarget())
   return;
 if (tryMergeCSharpKeywordVariables())
@@ -186,39 +184,6 @@
   return true;
 }
 
-// Merge 'argName' and ':' into a single token in `foo(argName: bar)`.
-bool FormatTokenLexer::tryMergeCSharpNamedArgument() {
-  if (Tokens.size() < 2)
-return false;
-  auto &Colon = *(Tokens.end() - 1);
-  if (!Colon->is(tok::colon))
-return false;
-
-  auto &Name = *(Tokens.end() - 2);
-  if (!Name->is(tok::identifier))
-return false;
-
-  const FormatToken *CommaOrLeftParen = nullptr;
-  for (auto I = Tokens.rbegin() + 2, E = Tokens.rend(); I != E; ++I) {
-// NB: Because previous pointers are not initialized yet, this cannot use
-// Token.getPreviousNonComment.
-if ((*I)->isNot(tok::comment)) {
-  CommaOrLeftParen = *I;
-  break;
-}
-  }
-
-  if (!CommaOrLeftParen || !CommaOrLeftParen->isOneOf(tok::l_paren, tok::comma))
-return false;
-
-  Name->TokenText = StringRef(Name->TokenText.begin(),
-  Colon->TokenText.end() - Name->TokenText.begin());
-  Name->ColumnWidth += Colon->ColumnWidth;
-  Name->Type = TT_CSharpNamedArgument;
-  Tokens.erase(Tokens.end() - 1);
-  return true;
-}
-
 // Search for verbatim or interpolated string literals @"ABC" or
 // $"a{abc}a" i and mark the token as TT_CSharpStringLi

[PATCH] D75006: [clang-format] Wrap lines for C# property accessors

2020-02-25 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked an inline comment as done.
jbcoe added inline comments.



Comment at: clang/unittests/Format/FormatTestCSharp.cpp:246
-   "get;\n"
-   "}");
 

MyDeveloperDay wrote:
> Nit: I feel like this layout should really be an option, (maybe for the 
> future).
> 
> When we originally did the C# work, we did say we might want in the future to 
> add options that might be specific like laying out the accessors 
> 
> I think VS has support for formatting them as either
> 
> ```
> public int Goo { set; get; }
> ```
> 
> and 
> 
> ```
> public int Goo
> {
>  set; get;
> }
> ```
> 
> and the following is equally valid in my eyes
> 
> ```
> public int Goo
> {
>  set; 
>  get;
> }
> ```
> 
> as well as what is being proposed here of
> 
> ```
> public int Goo
> {   set; get; }
> ```
> 
> I'm not completely sure how much the other options are controlling this at 
> present and how much is not in the control of your merging
> 
> and how does that change when there is actually code in the setter and getter?
> 
> 
> 
Agreed that this should be configured by an option in a future revision.


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

https://reviews.llvm.org/D75006



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


[PATCH] D75006: [clang-format] Wrap lines for C# property accessors

2020-02-24 Thread Jonathan B Coe via Phabricator via cfe-commits
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::const_iterator I,
+  SmallVectorImpl::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::const_iterator I,
 SmallVectorImpl::const_iterator E,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bi

[PATCH] D75006: Wrap lines for C# property accessors

2020-02-24 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 246170.
jbcoe added a comment.

Handle C# access modifier `internal `.

Fix typo in test for expression-bodied get/set methods.


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
@@ -554,5 +554,25 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(//
+int Value { get; set }
+string Name { get; private set }
+string AnotherName { protected get; private set }
+string YetAnotherName { internal get; internal set }
+double Sum { get })",
+   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,53 @@
 return 0;
   }
 
+  unsigned tryMergeCSharpPropertyAccessor(
+  SmallVectorImpl::const_iterator I,
+  SmallVectorImpl::const_iterator E, unsigned /*Limit*/) {
+// Does line start with `{`
+if (I[0]->Last->isNot(TT_FunctionLBrace))
+  return 0;
+
+// Does line start with `[access-modifier] get`
+if (I + 1 == E)
+  return 0;
+auto *GetToken = I[1]->First;
+if (GetToken && GetToken->isOneOf(tok::kw_public, tok::kw_protected,
+  tok::kw_private, Keywords.kw_internal))
+  GetToken = GetToken->Next;
+if (!GetToken || GetToken->TokenText != "get")
+  return 0;
+// Keep `get => some_code;` on a single line.
+if (GetToken->Next && GetToken->Next->isNot(tok::semi))
+  return 0;
+
+// Does line start with `[access-modifier] set` or `{`
+if (I + 2 == E)
+  return 0;
+auto *SetToken = I[2]->First;
+if (SetToken && SetToken->isOneOf(tok::kw_public, tok::kw_protected,
+  tok::kw_private, Keywords.kw_internal))
+  SetToken = SetToken->Next;
+
+if (SetToken && SetToken->is(tok::r_brace))
+  return 2;
+
+if (!SetToken || SetToken->TokenText != "set")
+  return 0;
+// Keep `set => some_code;` on a single line.
+if (SetToken->Next)
+  return 0;
+
+// Does line start with `}`
+if (I + 3 == E)
+  return 0;
+auto *RBrace = I[3]->First;
+if (!RBrace || !RBrace->is(tok::r_brace))
+  return 0;
+
+return 3;
+  }
+
   unsigned
   tryMergeSimplePPDirective(SmallVectorImpl::const_iterator I,
 SmallVectorImpl::const_iterator E,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D75006: Wrap lines for C# property accessors

2020-02-22 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 246070.
jbcoe added a comment.

Code and test to avoid wrapping accessors with expression body definitions.


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
@@ -554,5 +554,24 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  verifyFormat(R"(//
+int Value { get; set }
+string Name { get; private set }
+string AnotherName { protected get; private set }
+double Sum { get })",
+   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,53 @@
 return 0;
   }
 
+  unsigned tryMergeCSharpPropertyAccessor(
+  SmallVectorImpl::const_iterator I,
+  SmallVectorImpl::const_iterator E, unsigned /*Limit*/) {
+// Does line start with `{`
+if (I[0]->Last->isNot(TT_FunctionLBrace))
+  return 0;
+
+// Does line start with `[access-modifier] get`
+if (I + 1 == E)
+  return 0;
+auto *GetToken = I[1]->First;
+if (GetToken &&
+GetToken->isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private))
+  GetToken = GetToken->Next;
+if (!GetToken || GetToken->TokenText != "get")
+  return 0;
+// Keep `get => some_code;` on a single line.
+if (GetToken->Next && GetToken->Next->isNot(tok::semi))
+  return 0;
+
+// Does line start with `[access-modifier] set` or `{`
+if (I + 2 == E)
+  return 0;
+auto *SetToken = I[2]->First;
+if (SetToken &&
+SetToken->isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private))
+  SetToken = SetToken->Next;
+
+if (SetToken && SetToken->is(tok::r_brace))
+  return 2;
+
+if (!SetToken || SetToken->TokenText != "set")
+  return 0;
+// Keep `set => some_code;` on a single line.
+if (SetToken->Next)
+  return 0;
+
+// Does line start with `}`
+if (I + 3 == E)
+  return 0;
+auto *RBrace = I[3]->First;
+if (!RBrace || !RBrace->is(tok::r_brace))
+  return 0;
+
+return 3;
+  }
+
   unsigned
   tryMergeSimplePPDirective(SmallVectorImpl::const_iterator I,
 SmallVectorImpl::const_iterator E,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72401: Fixes for spaces around C# object initializers

2020-01-31 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 241694.
jbcoe added a comment.

Minor changes to address review comments.


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

https://reviews.llvm.org/D72401

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -457,5 +457,34 @@
   EXPECT_EQ(Code, format(Code, Style));
 }
 
+TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  // Start code fragemnts with a comment line so that C++ raw string literals
+  // as seen are identical to expected formatted code.
+
+  verifyFormat(R"(//
+Shape[] shapes = new[] {
+new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+},
+new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+},
+};)",
+   Style);
+
+  // 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,
+}};)",
+   Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2873,6 +2873,13 @@
   if (Left.is(tok::kw_using))
 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;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -457,5 +457,34 @@
   EXPECT_EQ(Code, format(Code, Style));
 }
 
+TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+
+  // Start code fragemnts with a comment line so that C++ raw string literals
+  // as seen are identical to expected formatted code.
+
+  verifyFormat(R"(//
+Shape[] shapes = new[] {
+new Circle {
+Radius = 2.7281,
+Colour = Colours.Red,
+},
+new Square {
+Side = 101.1,
+Colour = Colours.Yellow,
+},
+};)",
+   Style);
+
+  // 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,
+}};)",
+   Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2873,6 +2873,13 @@
   if (Left.is(tok::kw_using))
 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;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72144: Treat C# `using` as a control statement

2020-01-23 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 239836.
jbcoe added a comment.

Extended tests and added some comments explaining why seeming duplicated tests 
are useful.


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

https://reviews.llvm.org/D72144

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -235,20 +235,46 @@
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
   verifyFormat("public void foo () {\n"
"  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "  using () {}\n"
"}",
Style);
 
+  // Ensure clang-format affects top-level snippets correctly.
   verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
Style);
 
   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
   verifyFormat("public void foo() {\n"
"  using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
+   "  using() {}\n"
"}",
Style);
 
+  // Ensure clang-format affects top-level snippets correctly.
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "  using () {}\n"
+   "}",
+   Style);
+
+  // Ensure clang-format affects top-level snippets correctly.
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "  using() {}\n"
+   "}",
+   Style);
+
+  // Ensure clang-format affects top-level snippets correctly.
+  verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2869,7 +2869,8 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements 
||
+   spaceRequiredBeforeParens(Right);
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -235,20 +235,46 @@
   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
   verifyFormat("public void foo () {\n"
"  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "  using () {}\n"
"}",
Style);
 
+  // Ensure clang-format affects top-level snippets correctly.
   verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
Style);
 
   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
   verifyFormat("public void foo() {\n"
"  using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
+   "  using() {}\n"
"}",
Style);
 
+  // Ensure clang-format affects top-level snippets correctly.
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "  using () {}\n"
+   "}",
+   Style);
+
+  // Ensure clang-format affects top-level snippets correctly.
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "  using() {}\n"
+   "}",
+   Style);
+
+  // Ensure clang-format affects top-level snippets correctly.
+  verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/Tok

[PATCH] D72144: Treat C# `using` as a control statement

2020-01-22 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 239629.
jbcoe added a comment.

Removed test snippets that did not exercise new code.


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

https://reviews.llvm.org/D72144

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -238,8 +238,6 @@
"}",
Style);
 
-  verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
-   Style);
 
   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
   verifyFormat("public void foo() {\n"
@@ -247,7 +245,17 @@
"}",
Style);
 
-  verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "  using() {}\n"
+   "}",
Style);
 }
 
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2869,7 +2869,8 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements 
||
+   spaceRequiredBeforeParens(Right);
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -238,8 +238,6 @@
"}",
Style);
 
-  verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
-   Style);
 
   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
   verifyFormat("public void foo() {\n"
@@ -247,7 +245,17 @@
"}",
Style);
 
-  verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "  using() {}\n"
+   "}",
Style);
 }
 
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2869,7 +2869,8 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements ||
+   spaceRequiredBeforeParens(Right);
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72144: Treat C# `using` as a control statement

2020-01-22 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe marked 2 inline comments as done.
jbcoe added inline comments.



Comment at: clang/unittests/Format/FormatTestCSharp.cpp:259
+
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);

krasimir wrote:
> Can this appear at the top-level? If not, just keep the other test case to 
> avoid confusion.
I'm following the example set by by test cases above. I can remove (all) if you 
prefer and agree it does not test anything new.


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

https://reviews.llvm.org/D72144



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


[PATCH] D72144: Treat C# `using` as a control statement

2020-01-22 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 239574.
jbcoe added a comment.

Handle `using` case where SpaceBeforeParensOptions is set to 
SBPO_NonEmptyParentheses


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

https://reviews.llvm.org/D72144

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -249,6 +249,23 @@
 
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using() {}", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2869,7 +2869,8 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements 
||
+   spaceRequiredBeforeParens(Right);
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -249,6 +249,23 @@
 
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using() {}", Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2869,7 +2869,8 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements ||
+   spaceRequiredBeforeParens(Right);
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72401: Fixes for spaces around C# object initializers

2020-01-08 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
jbcoe added reviewers: MyDeveloperDay, klimek.

Fix spaces around typename and [] in C# object initializers.

Handling of newlines and binpacking will be addressed in a following revision - 
currently a trailing ',' is needed after the last argument to an object 
initializer to keep object initializer arguments on distinct lines.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72401

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -374,5 +374,22 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+
+  verifyFormat("Shape[] shapes = new[] {\n"
+   "new Circle {\n"
+   "Radius = 2.7281,\n"
+   "Colour = Colours.Red,\n"
+   "},\n"
+   "new Square {\n"
+   "Side = 101.1,\n"
+   "Colour = Colours.Yellow,\n"
+   "},\n"
+   "};",
+   Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2862,6 +2862,13 @@
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
 return spaceRequiredBeforeParens(Left);
+// space between ']' and '{'
+if (Left.is(tok::r_square) && Right.is(tok::l_brace))
+  return true;
+// space before '{' in "new MyType {"
+if (Left.is(TT_Unknown) && 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;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -374,5 +374,22 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+
+  verifyFormat("Shape[] shapes = new[] {\n"
+   "new Circle {\n"
+   "Radius = 2.7281,\n"
+   "Colour = Colours.Red,\n"
+   "},\n"
+   "new Square {\n"
+   "Side = 101.1,\n"
+   "Colour = Colours.Yellow,\n"
+   "},\n"
+   "};",
+   Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2862,6 +2862,13 @@
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
 return spaceRequiredBeforeParens(Left);
+// space between ']' and '{'
+if (Left.is(tok::r_square) && Right.is(tok::l_brace))
+  return true;
+// space before '{' in "new MyType {"
+if (Left.is(TT_Unknown) && 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;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72150: Allow space after C-style cast in C# code

2020-01-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a reviewer: klimek.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72150

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -374,5 +374,14 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  
+  verifyFormat("(int)x / y;", Style);
+  
+  Style.SpaceAfterCStyleCast = true; 
+  verifyFormat("(int) x / y;", Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1640,8 +1640,9 @@
 
   /// Determine whether ')' is ending a cast.
   bool rParenEndsCast(const FormatToken &Tok) {
-// C-style casts are only used in C++ and Java.
-if (!Style.isCpp() && Style.Language != FormatStyle::LK_Java)
+// C-style casts are only used in C++, C# and Java.
+if (!Style.isCSharp() && !Style.isCpp() && 
+Style.Language != FormatStyle::LK_Java)
   return false;
 
 // Empty parens aren't casts and there are no casts at the end of the line.


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -374,5 +374,14 @@
Style);
 }
 
+TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+  
+  verifyFormat("(int)x / y;", Style);
+  
+  Style.SpaceAfterCStyleCast = true; 
+  verifyFormat("(int) x / y;", Style);
+}
+
 } // namespace format
 } // end namespace clang
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1640,8 +1640,9 @@
 
   /// Determine whether ')' is ending a cast.
   bool rParenEndsCast(const FormatToken &Tok) {
-// C-style casts are only used in C++ and Java.
-if (!Style.isCpp() && Style.Language != FormatStyle::LK_Java)
+// C-style casts are only used in C++, C# and Java.
+if (!Style.isCSharp() && !Style.isCpp() && 
+Style.Language != FormatStyle::LK_Java)
   return false;
 
 // Empty parens aren't casts and there are no casts at the end of the line.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72144: Treat C# `using` as a control statement

2020-01-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe updated this revision to Diff 236035.
jbcoe added a reviewer: klimek.

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

https://reviews.llvm.org/D72144

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -249,6 +249,15 @@
 
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2861,7 +2861,7 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -249,6 +249,15 @@
 
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2861,7 +2861,7 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D72144: Treat C# `using` as a control statement

2020-01-03 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe created this revision.
jbcoe added a project: clang-format.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Unless SpaceBeforeParensOptions is set to SBPO_Never, a space will be put 
between `using` and `(` in C# code.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72144

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


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -249,6 +249,15 @@
 
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2763,7 +2763,7 @@
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
 (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while,
   tok::kw_switch, tok::kw_case, TT_ForEachMacro,
-  TT_ObjCForIn) ||
+  tok::kw_using, TT_ObjCForIn) ||
  Left.isIf(Line.Type != LT_PreprocessorDirective) ||
  (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
tok::kw_new, tok::kw_delete) &&
@@ -2861,7 +2861,7 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;


Index: clang/unittests/Format/FormatTestCSharp.cpp
===
--- clang/unittests/Format/FormatTestCSharp.cpp
+++ clang/unittests/Format/FormatTestCSharp.cpp
@@ -249,6 +249,15 @@
 
   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
Style);
+
+  Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
+  verifyFormat("public void foo() {\n"
+   "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
+   "}",
+   Style);
+
+  verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
+   Style);
 }
 
 TEST_F(FormatTestCSharp, CSharpRegions) {
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2763,7 +2763,7 @@
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
 (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while,
   tok::kw_switch, tok::kw_case, TT_ForEachMacro,
-  TT_ObjCForIn) ||
+  tok::kw_using, TT_ObjCForIn) ||
  Left.isIf(Line.Type != LT_PreprocessorDirective) ||
  (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
tok::kw_new, tok::kw_delete) &&
@@ -2861,7 +2861,7 @@
 // space between keywords and paren e.g. "using ("
 if (Right.is(tok::l_paren))
   if (Left.is(tok::kw_using))
-return spaceRequiredBeforeParens(Left);
+return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
   } else if (Style.Language == FormatStyle::LK_JavaScript) {
 if (Left.is(TT_JsFatArrow))
   return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51299: [python bindings] Expose template argument API for Type

2018-09-11 Thread Jonathan B Coe via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL341930: [python bindings] Expose getNumTemplateArguments 
(authored by jbcoe, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D51299

Files:
  cfe/trunk/bindings/python/clang/cindex.py
  cfe/trunk/bindings/python/tests/cindex/test_type.py


Index: cfe/trunk/bindings/python/clang/cindex.py
===
--- cfe/trunk/bindings/python/clang/cindex.py
+++ cfe/trunk/bindings/python/clang/cindex.py
@@ -2254,6 +2254,12 @@
 
 return res
 
+def get_num_template_arguments(self):
+return conf.lib.clang_Type_getNumTemplateArguments(self)
+
+def get_template_argument_type(self, num):
+return conf.lib.clang_Type_getTemplateArgumentAsType(self, num)
+
 def get_canonical(self):
 """
 Return the canonical type for a Type.
@@ -3999,6 +4005,15 @@
Type,
Type.from_result),
 
+  ("clang_Type_getNumTemplateArguments",
+   [Type],
+   c_int),
+
+  ("clang_Type_getTemplateArgumentAsType",
+   [Type, c_uint],
+   Type,
+   Type.from_result),
+
   ("clang_Type_getOffsetOf",
[Type, c_interop_string],
c_longlong),
Index: cfe/trunk/bindings/python/tests/cindex/test_type.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_type.py
+++ cfe/trunk/bindings/python/tests/cindex/test_type.py
@@ -436,3 +436,28 @@
 
 self.assertIsNotNone(testInteger, "Could not find testInteger.")
 self.assertEqual(testInteger.type.get_address_space(), 2)
+
+def test_template_arguments(self):
+source = """
+class Foo {
+};
+template 
+class Template {
+};
+Template instance;
+int bar;
+"""
+tu = get_tu(source, lang='cpp')
+
+# Varible with a template argument.
+cursor = get_cursor(tu, 'instance')
+cursor_type = cursor.type
+self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
+self.assertEqual(cursor_type.spelling, 'Template')
+self.assertEqual(cursor_type.get_num_template_arguments(), 1)
+template_type = cursor_type.get_template_argument_type(0)
+self.assertEqual(template_type.spelling, 'Foo')
+
+# Variable without a template argument.
+cursor = get_cursor(tu, 'bar')
+self.assertEqual(cursor.get_num_template_arguments(), -1)


Index: cfe/trunk/bindings/python/clang/cindex.py
===
--- cfe/trunk/bindings/python/clang/cindex.py
+++ cfe/trunk/bindings/python/clang/cindex.py
@@ -2254,6 +2254,12 @@
 
 return res
 
+def get_num_template_arguments(self):
+return conf.lib.clang_Type_getNumTemplateArguments(self)
+
+def get_template_argument_type(self, num):
+return conf.lib.clang_Type_getTemplateArgumentAsType(self, num)
+
 def get_canonical(self):
 """
 Return the canonical type for a Type.
@@ -3999,6 +4005,15 @@
Type,
Type.from_result),
 
+  ("clang_Type_getNumTemplateArguments",
+   [Type],
+   c_int),
+
+  ("clang_Type_getTemplateArgumentAsType",
+   [Type, c_uint],
+   Type,
+   Type.from_result),
+
   ("clang_Type_getOffsetOf",
[Type, c_interop_string],
c_longlong),
Index: cfe/trunk/bindings/python/tests/cindex/test_type.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_type.py
+++ cfe/trunk/bindings/python/tests/cindex/test_type.py
@@ -436,3 +436,28 @@
 
 self.assertIsNotNone(testInteger, "Could not find testInteger.")
 self.assertEqual(testInteger.type.get_address_space(), 2)
+
+def test_template_arguments(self):
+source = """
+class Foo {
+};
+template 
+class Template {
+};
+Template instance;
+int bar;
+"""
+tu = get_tu(source, lang='cpp')
+
+# Varible with a template argument.
+cursor = get_cursor(tu, 'instance')
+cursor_type = cursor.type
+self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
+self.assertEqual(cursor_type.spelling, 'Template')
+self.assertEqual(cursor_type.get_num_template_arguments(), 1)
+template_type = cursor_type.get_template_argument_type(0)
+self.assertEqual(template_type.spelling, 'Foo')
+
+# Variable without a template argument.
+cursor = get_cursor(tu, 'bar')
+self.assertEqual(cursor.get_num_template_arguments(), -1)
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51299: [python bindings] Expose template argument API for Type

2018-09-11 Thread Jonathan B Coe via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC341930: [python bindings] Expose getNumTemplateArguments 
(authored by jbcoe, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D51299?vs=162667&id=164854#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D51299

Files:
  bindings/python/clang/cindex.py
  bindings/python/tests/cindex/test_type.py


Index: bindings/python/clang/cindex.py
===
--- bindings/python/clang/cindex.py
+++ bindings/python/clang/cindex.py
@@ -2254,6 +2254,12 @@
 
 return res
 
+def get_num_template_arguments(self):
+return conf.lib.clang_Type_getNumTemplateArguments(self)
+
+def get_template_argument_type(self, num):
+return conf.lib.clang_Type_getTemplateArgumentAsType(self, num)
+
 def get_canonical(self):
 """
 Return the canonical type for a Type.
@@ -3999,6 +4005,15 @@
Type,
Type.from_result),
 
+  ("clang_Type_getNumTemplateArguments",
+   [Type],
+   c_int),
+
+  ("clang_Type_getTemplateArgumentAsType",
+   [Type, c_uint],
+   Type,
+   Type.from_result),
+
   ("clang_Type_getOffsetOf",
[Type, c_interop_string],
c_longlong),
Index: bindings/python/tests/cindex/test_type.py
===
--- bindings/python/tests/cindex/test_type.py
+++ bindings/python/tests/cindex/test_type.py
@@ -436,3 +436,28 @@
 
 self.assertIsNotNone(testInteger, "Could not find testInteger.")
 self.assertEqual(testInteger.type.get_address_space(), 2)
+
+def test_template_arguments(self):
+source = """
+class Foo {
+};
+template 
+class Template {
+};
+Template instance;
+int bar;
+"""
+tu = get_tu(source, lang='cpp')
+
+# Varible with a template argument.
+cursor = get_cursor(tu, 'instance')
+cursor_type = cursor.type
+self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
+self.assertEqual(cursor_type.spelling, 'Template')
+self.assertEqual(cursor_type.get_num_template_arguments(), 1)
+template_type = cursor_type.get_template_argument_type(0)
+self.assertEqual(template_type.spelling, 'Foo')
+
+# Variable without a template argument.
+cursor = get_cursor(tu, 'bar')
+self.assertEqual(cursor.get_num_template_arguments(), -1)


Index: bindings/python/clang/cindex.py
===
--- bindings/python/clang/cindex.py
+++ bindings/python/clang/cindex.py
@@ -2254,6 +2254,12 @@
 
 return res
 
+def get_num_template_arguments(self):
+return conf.lib.clang_Type_getNumTemplateArguments(self)
+
+def get_template_argument_type(self, num):
+return conf.lib.clang_Type_getTemplateArgumentAsType(self, num)
+
 def get_canonical(self):
 """
 Return the canonical type for a Type.
@@ -3999,6 +4005,15 @@
Type,
Type.from_result),
 
+  ("clang_Type_getNumTemplateArguments",
+   [Type],
+   c_int),
+
+  ("clang_Type_getTemplateArgumentAsType",
+   [Type, c_uint],
+   Type,
+   Type.from_result),
+
   ("clang_Type_getOffsetOf",
[Type, c_interop_string],
c_longlong),
Index: bindings/python/tests/cindex/test_type.py
===
--- bindings/python/tests/cindex/test_type.py
+++ bindings/python/tests/cindex/test_type.py
@@ -436,3 +436,28 @@
 
 self.assertIsNotNone(testInteger, "Could not find testInteger.")
 self.assertEqual(testInteger.type.get_address_space(), 2)
+
+def test_template_arguments(self):
+source = """
+class Foo {
+};
+template 
+class Template {
+};
+Template instance;
+int bar;
+"""
+tu = get_tu(source, lang='cpp')
+
+# Varible with a template argument.
+cursor = get_cursor(tu, 'instance')
+cursor_type = cursor.type
+self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
+self.assertEqual(cursor_type.spelling, 'Template')
+self.assertEqual(cursor_type.get_num_template_arguments(), 1)
+template_type = cursor_type.get_template_argument_type(0)
+self.assertEqual(template_type.spelling, 'Foo')
+
+# Variable without a template argument.
+cursor = get_cursor(tu, 'bar')
+self.assertEqual(cursor.get_num_template_arguments(), -1)
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51299: [python bindings] Expose template argument API for Type

2018-09-09 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

I can commit this. Thanks for the great work!


Repository:
  rC Clang

https://reviews.llvm.org/D51299



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


[PATCH] D47864: [python] Fix most Python binding unittests on Windows

2018-06-21 Thread Jonathan B Coe via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL335282: [bindings] Fix most Python binding unittests on 
Windows (authored by jbcoe, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D47864

Files:
  cfe/trunk/bindings/python/tests/cindex/test_cdb.py
  cfe/trunk/bindings/python/tests/cindex/test_cursor.py
  cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py

Index: cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
+++ cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
@@ -1,3 +1,4 @@
+from contextlib import contextmanager
 import gc
 import os
 import tempfile
@@ -19,15 +20,15 @@
 kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
 
 
+@contextmanager
 def save_tu(tu):
 """Convenience API to save a TranslationUnit to a file.
 
 Returns the filename it was saved to.
 """
-_, path = tempfile.mkstemp()
-tu.save(path)
-
-return path
+with tempfile.NamedTemporaryFile() as t:
+tu.save(t.name)
+yield t.name
 
 
 class TestTranslationUnit(unittest.TestCase):
@@ -125,10 +126,9 @@
 
 tu = get_tu('int foo();')
 
-path = save_tu(tu)
-self.assertTrue(os.path.exists(path))
-self.assertGreater(os.path.getsize(path), 0)
-os.unlink(path)
+with save_tu(tu) as path:
+self.assertTrue(os.path.exists(path))
+self.assertGreater(os.path.getsize(path), 0)
 
 def test_save_translation_errors(self):
 """Ensure that saving to an invalid directory raises."""
@@ -149,21 +149,18 @@
 
 tu = get_tu('int foo();')
 self.assertEqual(len(tu.diagnostics), 0)
-path = save_tu(tu)
-
-self.assertTrue(os.path.exists(path))
-self.assertGreater(os.path.getsize(path), 0)
-
-tu2 = TranslationUnit.from_ast_file(filename=path)
-self.assertEqual(len(tu2.diagnostics), 0)
+with save_tu(tu) as path:
+self.assertTrue(os.path.exists(path))
+self.assertGreater(os.path.getsize(path), 0)
 
-foo = get_cursor(tu2, 'foo')
-self.assertIsNotNone(foo)
+tu2 = TranslationUnit.from_ast_file(filename=path)
+self.assertEqual(len(tu2.diagnostics), 0)
 
-# Just in case there is an open file descriptor somewhere.
-del tu2
+foo = get_cursor(tu2, 'foo')
+self.assertIsNotNone(foo)
 
-os.unlink(path)
+# Just in case there is an open file descriptor somewhere.
+del tu2
 
 def test_index_parse(self):
 path = os.path.join(kInputsDir, 'hello.cpp')
Index: cfe/trunk/bindings/python/tests/cindex/test_cdb.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_cdb.py
+++ cfe/trunk/bindings/python/tests/cindex/test_cdb.py
@@ -5,11 +5,13 @@
 import os
 import gc
 import unittest
+import sys
 
 
 kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
 
 
+@unittest.skipIf(sys.platform == 'win32', "TODO: Fix these tests on Windows")
 class TestCDB(unittest.TestCase):
 def test_create_fail(self):
 """Check we fail loading a database with an assertion"""
Index: cfe/trunk/bindings/python/tests/cindex/test_cursor.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_cursor.py
+++ cfe/trunk/bindings/python/tests/cindex/test_cursor.py
@@ -335,7 +335,7 @@
 
 self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
 enum_type = enum.enum_type
-self.assertEqual(enum_type.kind, TypeKind.UINT)
+self.assertIn(enum_type.kind, (TypeKind.UINT, TypeKind.INT))
 
 def test_enum_type_cpp(self):
 tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
@@ -561,4 +561,4 @@
 # all valid manglings.
 # [c-index-test handles this by running the source through clang, emitting
 #  an AST file and running libclang on that AST file]
-self.assertIn(foo.mangled_name, ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH'))
+self.assertIn(foo.mangled_name, ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH', '?foo@@YAHHH@Z'))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D47864: [python] Fix most Python binding unittests on Windows

2018-06-21 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

Would you like me to commit this for you?


Repository:
  rC Clang

https://reviews.llvm.org/D47864



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


[PATCH] D46383: implementing Cursor.get_included_file in python bindings

2018-05-10 Thread Jonathan B Coe via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL332045: implementing Cursor.get_included_file in python 
bindings (authored by jbcoe, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D46383?vs=144992&id=146230#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D46383

Files:
  cfe/trunk/bindings/python/clang/cindex.py
  cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py


Index: cfe/trunk/bindings/python/clang/cindex.py
===
--- cfe/trunk/bindings/python/clang/cindex.py
+++ cfe/trunk/bindings/python/clang/cindex.py
@@ -1511,6 +1511,12 @@
 another translation unit."""
 return conf.lib.clang_getCursorUSR(self)
 
+def get_included_file(self):
+"""Returns the File that is included by the current inclusion 
cursor."""
+assert self.kind == CursorKind.INCLUSION_DIRECTIVE
+
+return conf.lib.clang_getIncludedFile(self)
+
 @property
 def kind(self):
 """Return the kind of this cursor."""
@@ -3085,8 +3091,9 @@
 return "" % (self.name)
 
 @staticmethod
-def from_cursor_result(res, fn, args):
-assert isinstance(res, File)
+def from_result(res, fn, args):
+assert isinstance(res, c_object_p)
+res = File(res)
 
 # Copy a reference to the TranslationUnit to prevent premature GC.
 res._tu = args[0]._tu
@@ -3701,8 +3708,8 @@
 
   ("clang_getIncludedFile",
[Cursor],
-   File,
-   File.from_cursor_result),
+   c_object_p,
+   File.from_result),
 
   ("clang_getInclusions",
[TranslationUnit, callbacks['translation_unit_includes'], py_object]),
Index: cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
+++ cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
@@ -108,6 +108,18 @@
 for i in zip(inc, tu.get_includes()):
 eq(i[0], i[1])
 
+def test_inclusion_directive(self):
+src = os.path.join(kInputsDir, 'include.cpp')
+h1 = os.path.join(kInputsDir, "header1.h")
+h2 = os.path.join(kInputsDir, "header2.h")
+h3 = os.path.join(kInputsDir, "header3.h")
+inc = [h1, h3, h2, h3, h1]
+
+tu = TranslationUnit.from_source(src, 
options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD)
+inclusion_directive_files = [c.get_included_file().name for c in 
tu.cursor.get_children() if c.kind == CursorKind.INCLUSION_DIRECTIVE]
+for i in zip(inc, inclusion_directive_files):
+self.assert_normpaths_equal(i[0], i[1])
+
 def test_save(self):
 """Ensure TranslationUnit.save() works."""
 


Index: cfe/trunk/bindings/python/clang/cindex.py
===
--- cfe/trunk/bindings/python/clang/cindex.py
+++ cfe/trunk/bindings/python/clang/cindex.py
@@ -1511,6 +1511,12 @@
 another translation unit."""
 return conf.lib.clang_getCursorUSR(self)
 
+def get_included_file(self):
+"""Returns the File that is included by the current inclusion cursor."""
+assert self.kind == CursorKind.INCLUSION_DIRECTIVE
+
+return conf.lib.clang_getIncludedFile(self)
+
 @property
 def kind(self):
 """Return the kind of this cursor."""
@@ -3085,8 +3091,9 @@
 return "" % (self.name)
 
 @staticmethod
-def from_cursor_result(res, fn, args):
-assert isinstance(res, File)
+def from_result(res, fn, args):
+assert isinstance(res, c_object_p)
+res = File(res)
 
 # Copy a reference to the TranslationUnit to prevent premature GC.
 res._tu = args[0]._tu
@@ -3701,8 +3708,8 @@
 
   ("clang_getIncludedFile",
[Cursor],
-   File,
-   File.from_cursor_result),
+   c_object_p,
+   File.from_result),
 
   ("clang_getInclusions",
[TranslationUnit, callbacks['translation_unit_includes'], py_object]),
Index: cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
+++ cfe/trunk/bindings/python/tests/cindex/test_translation_unit.py
@@ -108,6 +108,18 @@
 for i in zip(inc, tu.get_includes()):
 eq(i[0], i[1])
 
+def test_inclusion_directive(self):
+src = os.path.join(kInputsDir, 'include.cpp')
+h1 = os.path.join(kInputsDir, "header1.h")
+h2 = os.path.join(kInputsDir, "header2.h")
+h3 = os.path.join(kInputsDir, "header3.h")
+inc = [h1, h3, h2, h3, h1]
+
+tu = TranslationUnit.from_source(src, options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD)
+inclusion_directive_files = [c.get_included_file().name for c in tu.cursor.get_children() if c.ki

[PATCH] D46383: implementing Cursor.get_included_file in python bindings

2018-05-09 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

I will try to commit this today.


Repository:
  rC Clang

https://reviews.llvm.org/D46383



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


[PATCH] D45891: [clang-tidy] Improve bugprone-unused-return-value check

2018-04-24 Thread Jonathan B Coe via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCTE330772: [clang-tidy] Improve bugprone-unused-return-value 
check (authored by jbcoe, committed by ).

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45891

Files:
  clang-tidy/bugprone/UnusedReturnValueCheck.cpp
  docs/clang-tidy/checks/bugprone-unused-return-value.rst
  test/clang-tidy/bugprone-unused-return-value-custom.cpp
  test/clang-tidy/bugprone-unused-return-value.cpp

Index: test/clang-tidy/bugprone-unused-return-value.cpp
===
--- test/clang-tidy/bugprone-unused-return-value.cpp
+++ test/clang-tidy/bugprone-unused-return-value.cpp
@@ -24,6 +24,34 @@
 template 
 ForwardIt unique(ForwardIt, ForwardIt);
 
+template 
+struct default_delete;
+
+template >
+struct unique_ptr {
+  T *release() noexcept;
+};
+
+template 
+struct char_traits;
+
+template 
+struct allocator;
+
+template ,
+  typename Allocator = allocator>
+struct basic_string {
+  bool empty() const;
+};
+
+typedef basic_string string;
+
+template >
+struct vector {
+  bool empty() const noexcept;
+};
+
 // the check should be able to match std lib calls even if the functions are
 // declared inside inline namespaces
 inline namespace v1 {
@@ -64,6 +92,18 @@
   std::unique(nullptr, nullptr);
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
 
+  std::unique_ptr UPtr;
+  UPtr.release();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  std::string Str;
+  Str.empty();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  std::vector Vec;
+  Vec.empty();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
   // test discarding return values inside different kinds of statements
 
   auto Lambda = [] { std::remove(nullptr, nullptr, 1); };
@@ -137,6 +177,15 @@
 
   auto UniqueRetval = std::unique(nullptr, nullptr);
 
+  std::unique_ptr UPtrNoWarning;
+  auto ReleaseRetval = UPtrNoWarning.release();
+
+  std::string StrNoWarning;
+  auto StrEmptyRetval = StrNoWarning.empty();
+
+  std::vector VecNoWarning;
+  auto VecEmptyRetval = VecNoWarning.empty();
+
   // test using the return value in different kinds of expressions
   useFuture(std::async(increment, 42));
   std::launder(&FNoWarning)->f();
Index: test/clang-tidy/bugprone-unused-return-value-custom.cpp
===
--- test/clang-tidy/bugprone-unused-return-value-custom.cpp
+++ test/clang-tidy/bugprone-unused-return-value-custom.cpp
@@ -1,7 +1,7 @@
 // RUN: %check_clang_tidy %s bugprone-unused-return-value %t \
 // RUN: -config='{CheckOptions: \
 // RUN:  [{key: bugprone-unused-return-value.CheckedFunctions, \
-// RUN:value: "::fun;::ns::Outer::Inner::memFun;::ns::Type::staticFun"}]}' \
+// RUN:value: "::fun;::ns::Outer::Inner::memFun;::ns::Type::staticFun;::ns::ClassTemplate::memFun;::ns::ClassTemplate::staticFun"}]}' \
 // RUN: --
 
 namespace std {
@@ -34,6 +34,12 @@
   static Retval staticFun();
 };
 
+template 
+struct ClassTemplate {
+  Retval memFun();
+  static Retval staticFun();
+};
+
 } // namespace ns
 
 int fun();
@@ -60,6 +66,13 @@
 
   ns::Type::staticFun();
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  ns::ClassTemplate ObjA4;
+  ObjA4.memFun();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  ns::ClassTemplate::staticFun();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
 }
 
 void noWarning() {
@@ -70,13 +83,18 @@
 
   auto R3 = ns::Type::staticFun();
 
+  ns::ClassTemplate ObjB2;
+  auto R4 = ObjB2.memFun();
+
+  auto R5 = ns::ClassTemplate::staticFun();
+
   // test calling a void overload of a checked function
   fun(5);
 
   // test discarding return value of functions that are not configured to be checked
   int I = 1;
   std::launder(&I);
 
-  ns::Type ObjB2;
-  ObjB2.memFun();
+  ns::Type ObjB3;
+  ObjB3.memFun();
 }
Index: clang-tidy/bugprone/UnusedReturnValueCheck.cpp
===
--- clang-tidy/bugprone/UnusedReturnValueCheck.cpp
+++ clang-tidy/bugprone/UnusedReturnValueCheck.cpp
@@ -19,27 +19,45 @@
 namespace tidy {
 namespace bugprone {
 
+namespace {
+
+// Matches functions that are instantiated from a class template member function
+// matching InnerMatcher. Functions not instantiated from a class template
+// member function are matched directly with InnerMatcher.
+AST_MATCHER_P(FunctionDecl, isInstantia

[PATCH] D45891: [clang-tidy] Improve bugprone-unused-return-value check

2018-04-24 Thread Jonathan B Coe via Phabricator via cfe-commits
jbcoe added a comment.

I can merge this for you. Congratulations on the commit!


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45891



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


[PATCH] D45671: [python bindings] Fix Cursor.result_type for ObjC method declarations - Bug 36677

2018-04-22 Thread Jonathan B Coe via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL330557: [python bindings] Fix Cursor.result_type for ObjC 
method declarations - Bug… (authored by jbcoe, committed by ).

Repository:
  rL LLVM

https://reviews.llvm.org/D45671

Files:
  cfe/trunk/bindings/python/clang/cindex.py
  cfe/trunk/bindings/python/tests/cindex/test_cursor.py


Index: cfe/trunk/bindings/python/clang/cindex.py
===
--- cfe/trunk/bindings/python/clang/cindex.py
+++ cfe/trunk/bindings/python/clang/cindex.py
@@ -1644,7 +1644,7 @@
 def result_type(self):
 """Retrieve the Type of the result for this Cursor."""
 if not hasattr(self, '_result_type'):
-self._result_type = conf.lib.clang_getResultType(self.type)
+self._result_type = conf.lib.clang_getCursorResultType(self)
 
 return self._result_type
 
@@ -3568,6 +3568,11 @@
[Cursor, c_uint, c_uint],
SourceRange),
 
+  ("clang_getCursorResultType",
+   [Cursor],
+   Type,
+   Type.from_result),
+
   ("clang_getCursorSemanticParent",
[Cursor],
Cursor,
Index: cfe/trunk/bindings/python/tests/cindex/test_cursor.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_cursor.py
+++ cfe/trunk/bindings/python/tests/cindex/test_cursor.py
@@ -429,6 +429,18 @@
 t = foo.result_type
 self.assertEqual(t.kind, TypeKind.INT)
 
+def test_result_type_objc_method_decl(self):
+code = """\
+@interface Interface : NSObject
+-(void)voidMethod;
+@end
+"""
+tu = get_tu(code, lang='objc')
+cursor = get_cursor(tu, 'voidMethod')
+result_type = cursor.result_type
+self.assertEqual(cursor.kind, CursorKind.OBJC_INSTANCE_METHOD_DECL)
+self.assertEqual(result_type.kind, TypeKind.VOID)
+
 def test_availability(self):
 tu = get_tu('class A { A(A const&) = delete; };', lang='cpp')
 


Index: cfe/trunk/bindings/python/clang/cindex.py
===
--- cfe/trunk/bindings/python/clang/cindex.py
+++ cfe/trunk/bindings/python/clang/cindex.py
@@ -1644,7 +1644,7 @@
 def result_type(self):
 """Retrieve the Type of the result for this Cursor."""
 if not hasattr(self, '_result_type'):
-self._result_type = conf.lib.clang_getResultType(self.type)
+self._result_type = conf.lib.clang_getCursorResultType(self)
 
 return self._result_type
 
@@ -3568,6 +3568,11 @@
[Cursor, c_uint, c_uint],
SourceRange),
 
+  ("clang_getCursorResultType",
+   [Cursor],
+   Type,
+   Type.from_result),
+
   ("clang_getCursorSemanticParent",
[Cursor],
Cursor,
Index: cfe/trunk/bindings/python/tests/cindex/test_cursor.py
===
--- cfe/trunk/bindings/python/tests/cindex/test_cursor.py
+++ cfe/trunk/bindings/python/tests/cindex/test_cursor.py
@@ -429,6 +429,18 @@
 t = foo.result_type
 self.assertEqual(t.kind, TypeKind.INT)
 
+def test_result_type_objc_method_decl(self):
+code = """\
+@interface Interface : NSObject
+-(void)voidMethod;
+@end
+"""
+tu = get_tu(code, lang='objc')
+cursor = get_cursor(tu, 'voidMethod')
+result_type = cursor.result_type
+self.assertEqual(cursor.kind, CursorKind.OBJC_INSTANCE_METHOD_DECL)
+self.assertEqual(result_type.kind, TypeKind.VOID)
+
 def test_availability(self):
 tu = get_tu('class A { A(A const&) = delete; };', lang='cpp')
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >