diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -104,6 +104,7 @@ TYPE(CSharpStringLiteral) \ TYPE(CSharpNullCoalescing) \ TYPE(CSharpNamedArgumentColon) \ + TYPE(CSharpNullableTypeQuestionMark) \ TYPE(Unknown) enum TokenType { diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/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)) diff --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp --- a/clang/unittests/Format/FormatTestCSharp.cpp +++ b/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