Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions CodeBlocker.Test/TemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,71 @@ public void ABodyThatWritesOnlyBlankLinesRendersAsAnEmptyBlock(int newLines)
Assert.AreEqual("public void M() { }\n", Render(method));
}

[TestMethod]
public void ABodyThatWritesOnlyALineCommentIsBraced() =>
// "void M() // nothing to reset" has no body at all (CS1002).
Assert.AreEqual(
"void M()\n{\n\t// nothing to reset\n}\n",
Render(new MethodTemplate
{
Type = "void",
Name = "M",
BodyFactory = codeBlocker => codeBlocker.WriteLine("// nothing to reset"),
}));

[TestMethod]
public void ABodyThatWritesOnlyLineCommentsIsBraced() =>
Assert.AreEqual(
"void M()\n{\n\t// a\n\t// b\n}\n",
Render(new MethodTemplate
{
Type = "void",
Name = "M",
BodyFactory = codeBlocker =>
{
codeBlocker.WriteLine("// a");
codeBlocker.WriteLine("// b");
},
}));

[TestMethod]
public void AConstructorBodyThatWritesOnlyALineCommentIsBraced() =>
Assert.AreEqual(
"C()\n{\n\t// no state\n}\n",
Render(new ConstructorTemplate
{
Name = "C",
BodyFactory = codeBlocker => codeBlocker.WriteLine("// no state"),
}));

[TestMethod]
public void ABodyThatWritesOnlyAnEmptyPragmaScopeIsBraced() =>
Assert.AreEqual(
"void M()\n{\n\t#pragma warning disable CS0168\n\t#pragma warning restore CS0168\n}\n",
Render(new MethodTemplate
{
Type = "void",
Name = "M",
BodyFactory = codeBlocker =>
{
using PragmaScope pragma = new(codeBlocker, "CS0168");
},
}));

[TestMethod]
[DataRow("=> x;")]
[DataRow("{ }")]
[DataRow("=> x; // trailing")]
public void AOneLineBodyWithCodeStaysOnTheDeclarationLine(string body) =>
Assert.AreEqual(
$"int M() {body}\n",
Render(new MethodTemplate
{
Type = "int",
Name = "M",
BodyFactory = codeBlocker => codeBlocker.WriteLine(body),
}));

[TestMethod]
public void AnExpressionBodyBetweenBlankLinesStaysOnTheDeclarationLine() =>
Assert.AreEqual(
Expand Down
35 changes: 35 additions & 0 deletions CodeBlocker/Templates/TemplateRendering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,20 @@ internal static void WriteBody(CodeBlocker codeBlocker, Action<CodeBlocker>? bod
return;
}

// A comment or a directive is not a body either: written after the declaration it leaves the
// member with none, so a body made only of them is wrapped in braces instead. A generator
// writing "// no fields to reset" in place of an empty loop would otherwise emit CS1002.
if (!HasCode(lines))
{
codeBlocker.WriteLine();
using (new Scope(codeBlocker))
{
SpliceFragment(codeBlocker, body);
}

return;
}

if (contentLines.Length == 1)
{
// An expression body stays on the declaration line.
Expand Down Expand Up @@ -372,6 +386,27 @@ internal static void WriteExpressionBody(CodeBlocker codeBlocker, Action<CodeBlo
}
}

/// <summary>
/// Reports whether any line of a fragment holds code: something other than a line comment or a
/// preprocessor directive.
/// </summary>
/// <param name="lines">The lines of a fragment, as <see cref="SplitLines"/> returns them.</param>
/// <returns><see langword="true"/> if at least one line has code on it.</returns>
private static bool HasCode(string[] lines)
{
int[] codeEnds = FindCodeEnds(lines);
for (int i = 0; i < lines.Length; i++)
{
string code = lines[i][..codeEnds[i]].Trim();
if (code.Length != 0 && code[0] != '#')
{
return true;
}
}

return false;
}

/// <summary>
/// Finds where the code on each line ends: at the start of the line comment the line ends in,
/// or at the end of the line when it has none.
Expand Down
Loading