Browse Source

Fix #3406: Wrong decompilation of record struct without primary constructor.

pull/3455/head
Siegfried Pammer 3 months ago
parent
commit
453fc06e02
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 35
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3406.cs
  4. 6
      ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs
  5. 4
      ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -135,6 +135,7 @@
<Compile Include="TestCases\ILPretty\Issue3442.cs" /> <Compile Include="TestCases\ILPretty\Issue3442.cs" />
<Compile Include="TestCases\ILPretty\MonoFixed.cs" /> <Compile Include="TestCases\ILPretty\MonoFixed.cs" />
<Compile Include="TestCases\Pretty\Comparisons.cs" /> <Compile Include="TestCases\Pretty\Comparisons.cs" />
<Compile Include="TestCases\Pretty\Issue3406.cs" />
<Compile Include="TestCases\Pretty\Issue3439.cs" /> <Compile Include="TestCases\Pretty\Issue3439.cs" />
<Compile Include="TestCases\Pretty\Issue3442.cs" /> <Compile Include="TestCases\Pretty\Issue3442.cs" />
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" /> <None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -610,6 +610,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions); await RunForLibrary(cscOptions: cscOptions);
} }
[Test]
public async Task Issue3406([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
[Test] [Test]
public async Task Issue3442([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) public async Task Issue3442([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{ {

35
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3406.cs

@ -0,0 +1,35 @@
internal class Issue3406
{
private record struct S1(int Value);
private record struct S2
{
public int Value;
public S2(int value)
{
Value = value;
}
public S2(int a, int b)
{
Value = a + b;
}
}
private record struct S3
{
public int Value;
public S3(int value)
{
Value = value;
}
}
// This also generates a hidden backing field
private record struct S4(int value)
{
public int Value = value;
}
}

6
ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs

@ -222,10 +222,14 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
backingMember = property; backingMember = property;
} }
else else if (!recordTypeDef.IsRecord)
{ {
backingMember = field; backingMember = field;
} }
else
{
return false;
}
primaryCtorParameterToAutoPropertyOrBackingField.Add(unspecializedMethod.Parameters[i], backingMember); primaryCtorParameterToAutoPropertyOrBackingField.Add(unspecializedMethod.Parameters[i], backingMember);
autoPropertyOrBackingFieldToPrimaryCtorParameter.Add(backingMember, unspecializedMethod.Parameters[i]); autoPropertyOrBackingFieldToPrimaryCtorParameter.Add(backingMember, unspecializedMethod.Parameters[i]);

4
ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

@ -285,9 +285,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
case IProperty p: case IProperty p:
return record.IsPropertyDeclaredByPrimaryConstructor(p); return record.IsPropertyDeclaredByPrimaryConstructor(p);
case IField f: case IField f:
return true; return record.PrimaryConstructor != null;
case IEvent e: case IEvent e:
return true; return record.PrimaryConstructor != null;
default: default:
return false; return false;
} }

Loading…
Cancel
Save