Conversation
5c562c4 to
ac1fb34
Compare
|
LGTM, thank you @GBNikola! |
|
@uros-b who can merge this PR? |
|
@RyanSkraba can you check it as well here please? |
zcsizmadia
left a comment
There was a problem hiding this comment.
Thanks @GBNikola, the change does what it says. I checked that the new test fails without the fix and passes with it.
One regression in the generated output, though: the switch line now lands at column 0. For the test's Sample record:
public virtual object Get(int fieldPos)
{
- switch (fieldPos)
+switch (fieldPos)
{
case 0: return this.value;
default: throw new global::Avro.AvroRuntimeException("Bad index " + fieldPos + " in Get()");
- };
+ }
}Same for Put. The cause is how CodeDom's C# generator emits the two snippet types (CSharpCodeGenerator in dotnet/runtime):
- A
CodeSnippetExpressionis wrapped in aCodeExpressionStatement, so the generator writes the current indent, then the snippet, then;. That;is the unreachable statement this PR removes. The indent in front ofswitchalso came from the generator. - A
CodeSnippetStatementis written with the indent deliberately reset to 0 ("Don't indent snippet statements, in order to preserve the column information from the original code"), followed byOutput.WriteLine(e.Value).
Our snippet only indents itself partially. Every later line carries its own \t\t\t ("\t\t\tcase ", "\t\t\tdefault: ...", .Append("\t\t\t}")), but the builders start with a bare "switch (fieldPos)". Once the generator stops supplying the indent, only that first line loses it.
Since most users check the generated files in, this would show up as churn in their diffs. The fix is to seed both builders with the same indent the other lines use:
StringBuilder getFieldStmt = new StringBuilder("\t\t\tswitch (fieldPos)")
...
var putFieldStmt = new StringBuilder("\t\t\tswitch (fieldPos)")It would be good to assert that in the test as well, e.g. StringAssert.Contains("\t\t\tswitch (fieldPos)", sampleCode).
Optional, for consistency: the protocol callback Request switch at CodeGen.cs:585 uses the same CodeSnippetExpression pattern. Its cases end in break;, so the trailing ; isn't unreachable there, but switching it to CodeSnippetStatement (with the same indent handling) would keep the generator uniform.
avrogen built the Get()/Put() switch body via CodeSnippetExpression, which CodeDom wraps in a CodeExpressionStatement and always suffixes with a ";". Since every switch arm returns or throws, that trailing ";" is unreachable. Roslyn stays quiet about it, but IDE analyzers with fuller flow analysis (ReSharper/Rider) flag it, forcing consumers to suppress CS0162 for all avrogen output. Use CodeSnippetStatement instead, which emits the block verbatim with no appended semicolon.
… fix to protocol Request
ac1fb34 to
985e0ee
Compare
zcsizmadia
left a comment
There was a problem hiding this comment.
Thanks @GBNikola, all three points are addressed. I checked locally: with CodeGen.cs reverted, the new tests fail. With only the indent removed, the indent assertions fail. The generated output now differs from main only by the removed ; in Get/Put/Request. LGTM.
What is the purpose of the change
Fixes AVRO-4331. Generated
Get(int fieldPos)/Put(int fieldPos, object)build theirswitch body via
CodeSnippetExpression, whichCodeDomwraps in aCodeExpressionStatementand always suffixes with a;when emitting C#. Since everyswitch arm returns or throws, that trailing
;is an unreachable empty statement.Roslyn/
dotnet buildnever flags it, but IDE analyzers with fuller flow analysis(ReSharper/Rider) do, forcing consumers to add per-file suppressions for all avrogen
output.
This swaps
CodeSnippetExpressionforCodeSnippetStatement, which emits the switchblock verbatim with no appended semicolon. Both types live in
System.CodeDomand areavailable on every target framework the C# SDK already supports
(
netstandard2.0/netstandard2.1for the library,net6.0-net8.0for tests), sothere's no compatibility impact.
Verifying this change
This change added tests and can be verified as follows:
RecordGetAndPutSwitchesShouldNotEmitUnreachableStatementinCodeGenTest.cs,which generates a record and asserts the generated
Get/Putswitch has no stray;after its closing brace. Fails without the fix, passes with it.
Documentation