Browse Source

Fix #1698: Readonly auto properties from VB.NET are not properly decompiled

issue1638
Siegfried Pammer 4 years ago
parent
commit
bc5d078feb
  1. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1325.cs
  3. 39
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBPropertiesTest.cs
  4. 37
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBPropertiesTest.vb
  5. 8
      ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs
  6. 7
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  7. 11
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

2
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -107,6 +107,7 @@
<Compile Include="TestCases\Correctness\DeconstructionTests.cs" /> <Compile Include="TestCases\Correctness\DeconstructionTests.cs" />
<Compile Include="TestCases\Correctness\DynamicTests.cs" /> <Compile Include="TestCases\Correctness\DynamicTests.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" /> <Compile Include="TestCases\Correctness\StringConcat.cs" />
<Compile Include="TestCases\VBPretty\VBPropertiesTest.cs" />
<None Include="TestCases\ILPretty\Issue2260SwitchString.cs" /> <None Include="TestCases\ILPretty\Issue2260SwitchString.cs" />
<None Include="TestCases\Pretty\Records.cs" /> <None Include="TestCases\Pretty\Records.cs" />
<Compile Include="TestCases\VBPretty\Issue2192.cs" /> <Compile Include="TestCases\VBPretty\Issue2192.cs" />
@ -308,6 +309,7 @@
<None Include="TestCases\Pretty\Readme.txt" /> <None Include="TestCases\Pretty\Readme.txt" />
<None Include="TestCases\VBPretty\VBCompoundAssign.vb" /> <None Include="TestCases\VBPretty\VBCompoundAssign.vb" />
<None Include="TestCases\VBPretty\Async.vb" /> <None Include="TestCases\VBPretty\Async.vb" />
<None Include="TestCases\VBPretty\VBPropertiesTest.vb" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

6
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1325.cs

@ -1,6 +1,5 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -13,6 +12,8 @@ using Microsoft.VisualBasic.CompilerServices;
[assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
#pragma warning disable format
namespace Issue1325 namespace Issue1325
{ {
[StandardModule] [StandardModule]
@ -34,9 +35,6 @@ namespace Issue1325
internal class Test internal class Test
{ {
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
private string _Unparameterized;
public string Parameterized { public string Parameterized {
get { get {
throw new NotImplementedException(); throw new NotImplementedException();

39
ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBPropertiesTest.cs

@ -0,0 +1,39 @@
using System;
public class VBPropertiesTest
{
private int _fullProperty;
public int FullProperty {
get {
return _fullProperty;
}
set {
_fullProperty = value;
}
}
public int AutoProperty { get; set; }
#if ROSLYN
public int ReadOnlyAutoProperty { get; }
public VBPropertiesTest()
{
ReadOnlyAutoProperty = 32;
}
#endif
public void TestMethod()
{
FullProperty = 42;
_fullProperty = 24;
AutoProperty = 4711;
Console.WriteLine(AutoProperty);
Console.WriteLine(_fullProperty);
Console.WriteLine(FullProperty);
#if ROSLYN
Console.WriteLine(ReadOnlyAutoProperty);
#endif
}
}

37
ICSharpCode.Decompiler.Tests/TestCases/VBPretty/VBPropertiesTest.vb

@ -0,0 +1,37 @@
Imports System
Public Class VBPropertiesTest
Private _fullProperty As Integer
Property FullProperty As Integer
Get
Return _fullProperty
End Get
Set(value As Integer)
_fullProperty = value
End Set
End Property
Property AutoProperty As Integer
#If ROSLYN Then
ReadOnly Property ReadOnlyAutoProperty As Integer
Sub New()
Me.ReadOnlyAutoProperty = 32
End Sub
#End If
Sub TestMethod()
Me.FullProperty = 42
Me._fullProperty = 24
Me.AutoProperty = 4711
Console.WriteLine(Me.AutoProperty)
Console.WriteLine(Me._fullProperty)
Console.WriteLine(Me.FullProperty)
#If ROSLYN Then
Console.WriteLine(Me.ReadOnlyAutoProperty)
#End If
End Sub
End Class

8
ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs

@ -102,6 +102,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(options: options | CompilerOptions.Library); Run(options: options | CompilerOptions.Library);
} }
[Test]
public void VBPropertiesTest([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
Run(options: options | CompilerOptions.Library);
}
void Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) void Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null)
{ {
var vbFile = Path.Combine(TestCasePath, testName + ".vb"); var vbFile = Path.Combine(TestCasePath, testName + ".vb");
@ -115,7 +121,7 @@ namespace ICSharpCode.Decompiler.Tests
var executable = Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile); var executable = Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile);
var decompiled = Tester.DecompileCSharp(executable.PathToAssembly, settings); var decompiled = Tester.DecompileCSharp(executable.PathToAssembly, settings);
CodeAssert.FilesAreEqual(csFile, decompiled); CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray());
} }
} }
} }

7
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -386,7 +386,7 @@ namespace ICSharpCode.Decompiler.CSharp
static readonly Regex automaticPropertyBackingFieldRegex = new Regex(@"^<(.*)>k__BackingField$", static readonly Regex automaticPropertyBackingFieldRegex = new Regex(@"^<(.*)>k__BackingField$",
RegexOptions.Compiled | RegexOptions.CultureInvariant); RegexOptions.Compiled | RegexOptions.CultureInvariant);
static bool IsAutomaticPropertyBackingField(SRM.FieldDefinition field, MetadataReader metadata, out string propertyName) static bool IsAutomaticPropertyBackingField(FieldDefinition field, MetadataReader metadata, out string propertyName)
{ {
propertyName = null; propertyName = null;
var name = metadata.GetString(field.Name); var name = metadata.GetString(field.Name);
@ -396,6 +396,11 @@ namespace ICSharpCode.Decompiler.CSharp
propertyName = m.Groups[1].Value; propertyName = m.Groups[1].Value;
return true; return true;
} }
if (name.StartsWith("_", StringComparison.Ordinal))
{
propertyName = name.Substring(1);
return field.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.CompilerGenerated);
}
return false; return false;
} }

11
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -592,15 +592,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
}; };
bool CanTransformToAutomaticProperty(IProperty property) bool CanTransformToAutomaticProperty(IProperty property, bool accessorsMustBeCompilerGenerated)
{ {
if (!property.CanGet) if (!property.CanGet)
return false; return false;
if (!property.Getter.IsCompilerGenerated()) if (accessorsMustBeCompilerGenerated && !property.Getter.IsCompilerGenerated())
return false; return false;
if (property.Setter is IMethod setter) if (property.Setter is IMethod setter)
{ {
if (!setter.IsCompilerGenerated()) if (accessorsMustBeCompilerGenerated && !setter.IsCompilerGenerated())
return false; return false;
if (setter.HasReadonlyModifier()) if (setter.HasReadonlyModifier())
return false; return false;
@ -611,7 +611,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
PropertyDeclaration TransformAutomaticProperty(PropertyDeclaration propertyDeclaration) PropertyDeclaration TransformAutomaticProperty(PropertyDeclaration propertyDeclaration)
{ {
IProperty property = propertyDeclaration.GetSymbol() as IProperty; IProperty property = propertyDeclaration.GetSymbol() as IProperty;
if (!CanTransformToAutomaticProperty(property)) if (!CanTransformToAutomaticProperty(property, !property.DeclaringTypeDefinition.Fields.Any(f => f.Name == "_" + property.Name && f.IsCompilerGenerated())))
return null; return null;
IField field = null; IField field = null;
Match m = automaticPropertyPattern.Match(propertyDeclaration); Match m = automaticPropertyPattern.Match(propertyDeclaration);
@ -741,7 +741,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var mrr = parent.Annotation<MemberResolveResult>(); var mrr = parent.Annotation<MemberResolveResult>();
var field = mrr?.Member as IField; var field = mrr?.Member as IField;
if (field != null && IsBackingFieldOfAutomaticProperty(field, out var property) if (field != null && IsBackingFieldOfAutomaticProperty(field, out var property)
&& CanTransformToAutomaticProperty(property) && currentMethod.AccessorOwner != property) && CanTransformToAutomaticProperty(property, !(field.IsCompilerGenerated() && field.Name == "_" + property.Name))
&& currentMethod.AccessorOwner != property)
{ {
if (!property.CanSet && !context.Settings.GetterOnlyAutomaticProperties) if (!property.CanSet && !context.Settings.GetterOnlyAutomaticProperties)
return null; return null;

Loading…
Cancel
Save