diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs index 95195ad4d..5fbcc60c9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs @@ -119,7 +119,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests get; set; } - +#if CS60 + public List ReadOnlyPropertyList { + get; + } +#endif public Data MoreData { get; set; @@ -797,6 +801,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests otherItem.Data3.Nullable = 3m; return otherItem; } + + private Data Issue1345_FalsePositive() + { + return new Data { + ReadOnlyPropertyList = { + MyEnum2.c, + MyEnum2.d + } + }; + } #endif } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il index 2aa2e90c8..91e9772e6 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il @@ -245,6 +245,8 @@ .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .field private class [mscorlib]System.Collections.Generic.List`1 'k__BackingField' .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .field private initonly class [mscorlib]System.Collections.Generic.List`1 'k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .field private class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data 'k__BackingField' .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .field private valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/StructData 'k__BackingField' @@ -323,6 +325,18 @@ IL_0007: ret } // end of method Data::set_PropertyList + .method public hidebysig specialname + instance class [mscorlib]System.Collections.Generic.List`1 + get_ReadOnlyPropertyList() cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::'k__BackingField' + IL_0006: ret + } // end of method Data::get_ReadOnlyPropertyList + .method public hidebysig specialname instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data get_MoreData() cil managed @@ -517,6 +531,11 @@ .get instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_PropertyList() .set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::set_PropertyList(class [mscorlib]System.Collections.Generic.List`1) } // end of property Data::PropertyList + .property instance class [mscorlib]System.Collections.Generic.List`1 + ReadOnlyPropertyList() + { + .get instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_ReadOnlyPropertyList() + } // end of property Data::ReadOnlyPropertyList .property instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data MoreData() { @@ -2340,6 +2359,23 @@ IL_001b: ret } // end of method TestCases::Issue1345c + .method private hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data + Issue1345_FalsePositive() cil managed + { + // Code size 30 (0x1e) + .maxstack 8 + IL_0000: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::.ctor() + IL_0005: dup + IL_0006: callvirt instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_ReadOnlyPropertyList() + IL_000b: ldc.i4.0 + IL_000c: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) + IL_0011: dup + IL_0012: callvirt instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_ReadOnlyPropertyList() + IL_0017: ldc.i4.1 + IL_0018: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) + IL_001d: ret + } // end of method TestCases::Issue1345_FalsePositive + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { @@ -2363,13 +2399,13 @@ .size 40 } // end of class '__StaticArrayInitTypeSize=40' - .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=40' E0D2592373A0C161E56E266306CD8405CD719D19 at I_00005360 + .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=40' E0D2592373A0C161E56E266306CD8405CD719D19 at I_00005418 } // end of class '' // ============================================================= -.data cil I_00005360 = bytearray ( +.data cil I_00005418 = bytearray ( 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il index 0d065909f..03e666539 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il @@ -271,6 +271,9 @@ .field private class [mscorlib]System.Collections.Generic.List`1 'k__BackingField' .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .field private initonly class [mscorlib]System.Collections.Generic.List`1 'k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) .field private class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data 'k__BackingField' .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) @@ -352,6 +355,18 @@ IL_0007: ret } // end of method Data::set_PropertyList + .method public hidebysig specialname + instance class [mscorlib]System.Collections.Generic.List`1 + get_ReadOnlyPropertyList() cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::'k__BackingField' + IL_0006: ret + } // end of method Data::get_ReadOnlyPropertyList + .method public hidebysig specialname instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data get_MoreData() cil managed @@ -561,6 +576,11 @@ .get instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_PropertyList() .set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::set_PropertyList(class [mscorlib]System.Collections.Generic.List`1) } // end of property Data::PropertyList + .property instance class [mscorlib]System.Collections.Generic.List`1 + ReadOnlyPropertyList() + { + .get instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_ReadOnlyPropertyList() + } // end of property Data::ReadOnlyPropertyList .property instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data MoreData() { @@ -2696,6 +2716,31 @@ IL_0023: ret } // end of method TestCases::Issue1345c + .method private hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data + Issue1345_FalsePositive() cil managed + { + // Code size 37 (0x25) + .maxstack 3 + .locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data V_0) + IL_0000: nop + IL_0001: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::.ctor() + IL_0006: dup + IL_0007: callvirt instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_ReadOnlyPropertyList() + IL_000c: ldc.i4.0 + IL_000d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) + IL_0012: nop + IL_0013: dup + IL_0014: callvirt instance class [mscorlib]System.Collections.Generic.List`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests.TestCases/Data::get_ReadOnlyPropertyList() + IL_0019: ldc.i4.1 + IL_001a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) + IL_001f: nop + IL_0020: stloc.0 + IL_0021: br.s IL_0023 + + IL_0023: ldloc.0 + IL_0024: ret + } // end of method TestCases::Issue1345_FalsePositive + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { @@ -2720,13 +2765,13 @@ .size 40 } // end of class '__StaticArrayInitTypeSize=40' - .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=40' E0D2592373A0C161E56E266306CD8405CD719D19 at I_00005694 + .field static assembly initonly valuetype ''/'__StaticArrayInitTypeSize=40' E0D2592373A0C161E56E266306CD8405CD719D19 at I_00005764 } // end of class '' // ============================================================= -.data cil I_00005694 = bytearray ( +.data cil I_00005764 = bytearray ( 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00) diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs index f2c0674c7..b2eb71718 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs @@ -265,7 +265,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms instruction = call.Arguments[0]; if (method.IsAccessor) { var property = method.AccessorOwner as IProperty; - if (!property.CanSet || !(property.Accessibility == property.Setter.Accessibility || IsAccessorAccessible(property.Setter, resolveContext))) goto default; + if (!CanBeUsedInInitializer(property, resolveContext, kind, path)) goto default; var isGetter = method.Equals(property?.Getter); var indices = call.Arguments.Skip(1).Take(call.Arguments.Count - (isGetter ? 1 : 2)).ToArray(); if (indices.Length > 0 && !settings.DictionaryInitializers) goto default; @@ -293,7 +293,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } break; case LdObj ldobj: { - if (ldobj.Target is LdFlda ldflda && !ldflda.Field.IsReadOnly) { + if (ldobj.Target is LdFlda ldflda && (kind != AccessPathKind.Setter || !ldflda.Field.IsReadOnly)) { path.Insert(0, new AccessPathElement(ldobj.OpCode, ldflda.Field)); instruction = ldflda.Target; break; @@ -335,6 +335,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms return (kind, path, values, target); } + private static bool CanBeUsedInInitializer(IProperty property, CSharpTypeResolveContext resolveContext, AccessPathKind kind, List path) + { + if (property.CanSet && (property.Accessibility == property.Setter.Accessibility || IsAccessorAccessible(property.Setter, resolveContext))) + return true; + return kind != AccessPathKind.Setter; + } + private static bool IsAccessorAccessible(IMethod setter, CSharpTypeResolveContext resolveContext) { if (resolveContext == null)