Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3520,6 +3520,17 @@ return false; if (Right.is(TT_CSharpGenericTypeConstraint)) return true; + + // Break after C# [...] and before public/protected/private/internal. + if (Left.is(TT_AttributeSquare) && Left.is(tok::r_square) && + (Right.isAccessSpecifier(/*ColonRequired=*/false) || + Right.is(Keywords.kw_internal))) + return true; + // Break between ] and [ but only when its really 2 attributes. + if (Left.is(TT_AttributeSquare) && Right.is(TT_AttributeSquare) && + Left.is(tok::r_square) && Right.is(tok::l_square)) + return true; + } 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 && Index: clang/unittests/Format/FormatTestCSharp.cpp =================================================================== --- clang/unittests/Format/FormatTestCSharp.cpp +++ clang/unittests/Format/FormatTestCSharp.cpp @@ -247,6 +247,37 @@ verifyFormat("[TestMethod]\n" "public string Host { set; get; }"); + // Adjacent properties should not cause line wrapping issues + verifyFormat("[JsonProperty(\"foo\")]\n" + "public string Foo { set; get; }\n" + "[JsonProperty(\"bar\")]\n" + "public string Bar { set; get; }\n" + "[JsonProperty(\"bar\")]\n" + "protected string Bar { set; get; }\n" + "[JsonProperty(\"bar\")]\n" + "internal string Bar { set; get; }"); + + // Multiple attributes should always be split (not just the first ones) + verifyFormat("[XmlIgnore]\n" + "[JsonProperty(\"foo\")]\n" + "public string Foo { set; get; }"); + + verifyFormat("[XmlIgnore]\n" + "[JsonProperty(\"foo\")]\n" + "public string Foo { set; get; }\n" + "[XmlIgnore]\n" + "[JsonProperty(\"bar\")]\n" + "public string Bar { set; get; }"); + + verifyFormat("[XmlIgnore]\n" + "[ScriptIgnore]\n" + "[JsonProperty(\"foo\")]\n" + "public string Foo { set; get; }\n" + "[XmlIgnore]\n" + "[ScriptIgnore]\n" + "[JsonProperty(\"bar\")]\n" + "public string Bar { set; get; }"); + verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server " "listening on provided host\")]\n" "public string Host { set; get; }"); @@ -271,6 +302,34 @@ "{\n" "}"); + verifyFormat("void MethodA([In, Out] ref double x)\n" + "{\n" + "}"); + + verifyFormat("void MethodA([In, Out] double[] x)\n" + "{\n" + "}"); + + verifyFormat("void MethodA([In] double[] x)\n" + "{\n" + "}"); + + verifyFormat("void MethodA(int[] x)\n" + "{\n" + "}"); + verifyFormat("void MethodA(int[][] x)\n" + "{\n" + "}"); + verifyFormat("void MethodA([] x)\n" + "{\n" + "}"); + + verifyFormat("public void Log([CallerLineNumber] int line = -1, " + "[CallerFilePath] string path = null,\n" + " [CallerMemberName] string name = null)\n" + "{\n" + "}"); + // [] in an attribute do not cause premature line wrapping or indenting. verifyFormat(R"(// public class A