[clang-format] Wrap lines for C# property accessors
Summary: Ensure that auto-implemented properties `{ get; private set }` are wrapped on to one line for C# code. Reviewers: MyDeveloperDay, krasimir Reviewed By: MyDeveloperDay, krasimir Subscribers: cfe-commits Tags: #clang-format, #clang Differential Revision: https://reviews.llvm.org/D75006
This commit is contained in:
parent
edae4be8e2
commit
2bd6974aaa
|
@ -292,6 +292,13 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// Try to merge a function block with left brace unwrapped
|
||||||
if (TheLine->Last->is(TT_FunctionLBrace) &&
|
if (TheLine->Last->is(TT_FunctionLBrace) &&
|
||||||
TheLine->First != TheLine->Last) {
|
TheLine->First != TheLine->Last) {
|
||||||
|
@ -421,6 +428,64 @@ private:
|
||||||
return 0;
|
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<AnnotatedLine *>::const_iterator I,
|
||||||
|
SmallVectorImpl<AnnotatedLine *>::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
|
unsigned
|
||||||
tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
|
||||||
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
|
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
|
||||||
|
|
|
@ -240,18 +240,12 @@ TEST_F(FormatTestCSharp, Attributes) {
|
||||||
|
|
||||||
verifyFormat("[TestMethod]\n"
|
verifyFormat("[TestMethod]\n"
|
||||||
"public string Host\n"
|
"public string Host\n"
|
||||||
"{\n"
|
"{ set; get; }");
|
||||||
" set;\n"
|
|
||||||
" get;\n"
|
|
||||||
"}");
|
|
||||||
|
|
||||||
verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
|
verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
|
||||||
"listening on provided host\")]\n"
|
"listening on provided host\")]\n"
|
||||||
"public string Host\n"
|
"public string Host\n"
|
||||||
"{\n"
|
"{ set; get; }");
|
||||||
" set;\n"
|
|
||||||
" get;\n"
|
|
||||||
"}");
|
|
||||||
|
|
||||||
verifyFormat(
|
verifyFormat(
|
||||||
"[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
|
"[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
|
||||||
|
@ -554,5 +548,32 @@ PrintOrderDetails(orderNum: 31, productName: "Red Mug", // comment
|
||||||
Style);
|
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
|
} // namespace format
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
Loading…
Reference in New Issue