[clang-format] Special handling of spaces for C# code

Summary:
Ensure that there are spaces around braces '{', '}'.

Ensure that there is a space before and after '=>'.

Ensure that 'async' and 'when' are considered as keywords when inserting spaces.

Reviewers: krasimir, MyDeveloperDay

Reviewed By: krasimir

Tags: #clang-format

Differential Revision: https://reviews.llvm.org/D75129
This commit is contained in:
Jonathan Coe 2020-02-26 15:13:09 +00:00
parent 02323a3d5f
commit e8c5fea243
3 changed files with 51 additions and 14 deletions

View File

@ -771,6 +771,7 @@ struct AdditionalKeywords {
kw_unchecked = &IdentTable.get("unchecked");
kw_unsafe = &IdentTable.get("unsafe");
kw_ushort = &IdentTable.get("ushort");
kw_when = &IdentTable.get("when");
// Keep this at the end of the constructor to make sure everything here
// is
@ -787,7 +788,7 @@ struct AdditionalKeywords {
kw_fixed, kw_foreach, kw_implicit, kw_in, kw_interface, kw_internal,
kw_is, kw_lock, kw_null, kw_object, kw_out, kw_override, kw_params,
kw_readonly, kw_ref, kw_string, kw_stackalloc, kw_sbyte, kw_sealed,
kw_uint, kw_ulong, kw_unchecked, kw_unsafe, kw_ushort,
kw_uint, kw_ulong, kw_unchecked, kw_unsafe, kw_ushort, kw_when,
// Keywords from the JavaScript section.
kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from,
kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly,
@ -891,6 +892,7 @@ struct AdditionalKeywords {
IdentifierInfo *kw_unchecked;
IdentifierInfo *kw_unsafe;
IdentifierInfo *kw_ushort;
IdentifierInfo *kw_when;
/// Returns \c true if \p Tok is a true JavaScript identifier, returns
/// \c false if it is a keyword or a pseudo keyword.

View File

@ -2870,21 +2870,34 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin();
} else if (Style.isCSharp()) {
// Require spaces around '{' and before '}' unless they appear in
// interpolated strings. Interpolated strings are merged into a single token
// so cannot have spaces inserted by this function.
// Space before { (including space within '{ {').
if (Right.is(tok::l_brace))
return true;
// Spaces inside braces.
if (Left.is(tok::l_brace) && Right.isNot(tok::r_brace))
return true;
if (Left.isNot(tok::l_brace) && Right.is(tok::r_brace))
return true;
// Spaces around '=>'.
if (Left.is(TT_JsFatArrow) || Right.is(TT_JsFatArrow))
return true;
// space between type and variable e.g. Dictionary<string,string> foo;
if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
return true;
// space between keywords and paren e.g. "using ("
if (Right.is(tok::l_paren))
if (Left.is(tok::kw_using))
if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when))
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;

View File

@ -525,11 +525,11 @@ Shape[] shapes = new[] {
// 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);
}
@ -575,5 +575,27 @@ public string Name {
Style);
}
TEST_F(FormatTestCSharp, CSharpSpaces) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
Style.SpaceBeforeSquareBrackets = false;
Style.SpacesInSquareBrackets = false;
Style.SpaceBeforeCpp11BracedList = true;
Style.Cpp11BracedListStyle = false;
Style.SpacesInContainerLiterals = false;
verifyFormat(R"(new Car { "Door", 0.1 })", Style);
verifyFormat(R"(new Car { 0.1, "Door" })", Style);
verifyFormat(R"(new string[] { "A" })", Style);
verifyFormat(R"(new string[] {})", Style);
verifyFormat(R"(new Car { someVariableName })", Style);
verifyFormat(R"(new Car { someVariableName })", Style);
verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)",
Style);
verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style);
verifyFormat(R"(bool[] xs = { true, true };)", Style);
verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
}
} // namespace format
} // end namespace clang