Skip to content

Commit

Permalink
[clang-format] Merge name and colon into a single token for C# named …
Browse files Browse the repository at this point in the history
…arguments

Summary:
Merge 'argumentName' and ':' into a single token in foo(argumentName: bar).

Add C# named argument as a token type.

Reviewers: krasimir, MyDeveloperDay

Reviewed By: krasimir

Tags: #clang-format

Differential Revision: https://reviews.llvm.org/D74894
  • Loading branch information
jbcoe committed Feb 20, 2020
1 parent e2c2eb0 commit a11ff39
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 1 deletion.
1 change: 1 addition & 0 deletions clang/lib/Format/FormatToken.h
Expand Up @@ -103,6 +103,7 @@ namespace format {
TYPE(UnaryOperator) \
TYPE(CSharpStringLiteral) \
TYPE(CSharpNullCoalescing) \
TYPE(CSharpNamedArgument) \
TYPE(Unknown)

enum TokenType {
Expand Down
35 changes: 35 additions & 0 deletions clang/lib/Format/FormatTokenLexer.cpp
Expand Up @@ -76,6 +76,8 @@ void FormatTokenLexer::tryMergePreviousTokens() {
return;

if (Style.isCSharp()) {
if (tryMergeCSharpNamedArgument())
return;
if (tryMergeCSharpAttributeAndTarget())
return;
if (tryMergeCSharpKeywordVariables())
Expand Down Expand Up @@ -184,6 +186,39 @@ bool FormatTokenLexer::tryMergeJSPrivateIdentifier() {
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
// $"aaaaa{abc}aaaaa" i and mark the token as TT_CSharpStringLiteral, and to
// prevent splitting of @, $ and ".
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/FormatTokenLexer.h
Expand Up @@ -56,6 +56,7 @@ class FormatTokenLexer {
bool tryMergeCSharpDoubleQuestion();
bool tryTransformCSharpForEach();
bool tryMergeCSharpAttributeAndTarget();
bool tryMergeCSharpNamedArgument();

bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType);

Expand Down
17 changes: 16 additions & 1 deletion clang/unittests/Format/FormatTestCSharp.cpp
Expand Up @@ -513,7 +513,7 @@ var x = foo(className, $@"some code:
TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);

// Start code fragemnts with a comment line so that C++ raw string literals
// Start code fragments with a comment line so that C++ raw string literals
// as seen are identical to expected formatted code.

verifyFormat(R"(//
Expand All @@ -539,5 +539,20 @@ Shape[] shapes = new[] {new Circle {Radius = 2.7281, Colour = Colours.Red},
Style);
}

TEST_F(FormatTestCSharp, CSharpNamedArguments) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);

verifyFormat(R"(//
PrintOrderDetails(orderNum: 31, productName: "Red Mug",
sellerName: "Gift Shop");)",
Style);

// Ensure that trailing comments do not cause problems.
verifyFormat(R"(//
PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment
sellerName: "Gift Shop");)",
Style);
}

} // namespace format
} // end namespace clang

0 comments on commit a11ff39

Please sign in to comment.