From 18481efc44ce2a019e451834a1510eb8c0163e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Thu, 29 Sep 2022 21:32:19 +0200 Subject: [PATCH 1/3] Fix initialization of FakeProperty with setter Seems like a typo - the setter method was assigned to the Getter property The test GuessAccessors needed adjustments in the generated code. ILSpy is more eager to merge property assignments --- .../TestCases/ILPretty/GuessAccessors.cs | 30 ++++++++----------- .../TypeSystem/MetadataModule.cs | 2 +- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs index 37d64c6e5..f6ddbbd3f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs @@ -15,9 +15,8 @@ namespace ClassLibrary1 //IL_0007: Expected O, but got Unknown UnknownClass val = new UnknownClass(); int? unknownProperty = val.UnknownProperty; - int? num = unknownProperty.GetValueOrDefault(); - val.UnknownProperty = num; - int? num2 = num; + int? num2 = (val.UnknownProperty = unknownProperty.GetValueOrDefault()); + int? num3 = num2; List list = new List { val[unknownProperty.Value] ?? "", val.NotProperty, @@ -51,10 +50,9 @@ namespace ClassLibrary1 //IL_00e1: Expected O, but got Unknown //IL_00e1: Expected O, but got Unknown UnknownGenericClass val = new UnknownGenericClass(); - UnknownEventArgs unknownProperty = val.UnknownProperty; - val.UnknownProperty = unknownProperty; + UnknownEventArgs val2 = (val.UnknownProperty = val.UnknownProperty); List list = new List { - val[((object)unknownProperty).GetHashCode()] ?? "", + val[((object)val2).GetHashCode()] ?? "", val.NotProperty, val.get_NotPropertyWithGeneric(42), val[42], @@ -63,18 +61,17 @@ namespace ClassLibrary1 }; val.OnEvent += Instance_OnEvent; val.OnEvent -= Instance_OnEvent; - UnknownEventArgs val2 = val[(UnknownEventArgs)null]; - val[new UnknownEventArgs()] = val2; - UnknownEventArgs val3 = val[new UnknownEventArgs(), new UnknownEventArgs()]; - val[new UnknownEventArgs(), new UnknownEventArgs()] = val3; + UnknownEventArgs val3 = val[(UnknownEventArgs)null]; + val[new UnknownEventArgs()] = val3; + UnknownEventArgs val4 = val[new UnknownEventArgs(), new UnknownEventArgs()]; + val[new UnknownEventArgs(), new UnknownEventArgs()] = val4; } public void MethodUnknownStatic() { - int? unknownProperty = UnknownStaticClass.UnknownProperty; - UnknownStaticClass.UnknownProperty = unknownProperty; + int? num = (UnknownStaticClass.UnknownProperty = UnknownStaticClass.UnknownProperty); List list = new List { - UnknownStaticClass[unknownProperty.Value] ?? "", + UnknownStaticClass[num.Value] ?? "", UnknownStaticClass.NotProperty, UnknownStaticClass.get_NotPropertyWithGeneric(42), UnknownStaticClass[42], @@ -87,10 +84,9 @@ namespace ClassLibrary1 public void MethodUnknownStaticGeneric() { - string unknownProperty = UnknownStaticGenericClass.UnknownProperty; - UnknownStaticGenericClass.UnknownProperty = unknownProperty; + string text = (UnknownStaticGenericClass.UnknownProperty = UnknownStaticGenericClass.UnknownProperty); List list = new List { - UnknownStaticGenericClass[unknownProperty.Length] ?? "", + UnknownStaticGenericClass[text.Length] ?? "", UnknownStaticGenericClass.NotProperty, UnknownStaticGenericClass.get_NotPropertyWithGeneric(42), UnknownStaticGenericClass[42], @@ -121,4 +117,4 @@ namespace ClassLibrary1 throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs index 818e1ecd9..cf6ae1be5 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs +++ b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs @@ -670,7 +670,7 @@ namespace ICSharpCode.Decompiler.TypeSystem m.AccessorKind = MethodSemanticsAttributes.Setter; m.AccessorOwner = fakeProperty; - fakeProperty.Getter = m; + fakeProperty.Setter = m; fakeProperty.ReturnType = parameters.Last().Type; fakeProperty.IsIndexer = parameters.Count > 1; fakeProperty.Parameters = parameters.SkipLast(1).ToArray(); From 6153f9cf3518f90e0bac79487d49200a034a762d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Wed, 5 Oct 2022 16:27:53 +0200 Subject: [PATCH 2/3] Add test for indexer initializers --- .../TestCases/ILPretty/GuessAccessors.cs | 9 ++++++++ .../TestCases/ILPretty/GuessAccessors.il | 22 +++++++++++++++++++ ICSharpCode.Decompiler/CSharp/CallBuilder.cs | 2 ++ 3 files changed, 33 insertions(+) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs index f6ddbbd3f..c9e0f56e0 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.cs @@ -97,6 +97,15 @@ namespace ClassLibrary1 UnknownStaticGenericClass.OnEvent -= Instance_OnEvent; } + public void MethodUnknownIndexerInitializer() + { + //IL_0006: Unknown result type (might be due to invalid IL or missing references) + new UnknownClass { + ["a"] = 1, + ["b"] = 2 + }; + } + private void Instance_OnEvent(object sender, EventArgs e) { throw new NotImplementedException(); diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.il index 7fd6756ec..35fe005d1 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/GuessAccessors.il @@ -378,6 +378,28 @@ IL_0098: ret } // end of method UnknownClassTest::MethodUnknownStaticGeneric + .method public hidebysig + instance void MethodUnknownIndexerInitializer () cil managed + { + // Method begins at RVA 0x2050 + // Code size 32 (0x20) + .maxstack 8 + + IL_0000: nop + IL_0001: newobj instance void [UnknownAssembly]UnknownNamespace.UnknownClass::.ctor() + IL_0006: dup + IL_0007: ldstr "a" + IL_000c: ldc.i4.1 + IL_000d: callvirt instance void [UnknownAssembly]UnknownNamespace.UnknownClass::set_Item(string, int32) + IL_0012: nop + IL_0013: ldstr "b" + IL_0018: ldc.i4.2 + IL_0019: callvirt instance void [UnknownAssembly]UnknownNamespace.UnknownClass::set_Item(string, int32) + IL_001e: nop + IL_001f: ret + } // end of method C::MethodUnknownIndexerInitializer + + .method /* 100663301 */ private hidebysig instance void Instance_OnEvent ( object sender, diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index 5213febe3..ddbc92759 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -539,6 +539,8 @@ namespace ICSharpCode.Decompiler.CSharp public ExpressionWithResolveResult BuildDictionaryInitializerExpression(OpCode callOpCode, IMethod method, InitializedObjectResolveResult target, IReadOnlyList indices, ILInstruction value = null) { + if (method is null) + throw new ArgumentNullException(nameof(method)); ExpectedTargetDetails expectedTargetDetails = new ExpectedTargetDetails { CallOpCode = callOpCode }; var callArguments = new List(); From 93eecf93a54522d097d27d41536cba2c3e96f282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Thu, 29 Sep 2022 21:33:36 +0200 Subject: [PATCH 3/3] Add more asserts and ToStrings around the FakeProperty.Setter problem --- ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs | 1 + .../TypeSystem/Implementation/FakeMember.cs | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index e96407395..e11a9e10d 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -3340,6 +3340,7 @@ namespace ICSharpCode.Decompiler.CSharp { var property = (IProperty)lastElement.Member; Debug.Assert(property.IsIndexer); + Debug.Assert(property.Setter != null, $"Indexer property {property} has no setter"); elementsStack.Peek().Add( new CallBuilder(this, typeSystem, settings) .BuildDictionaryInitializerExpression(lastElement.OpCode, property.Setter, initObjRR, GetIndices(lastElement.Indices, indexVariables).ToList(), info.Values.Single()) diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs index 43549b6c6..2c4a2f67e 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs @@ -199,6 +199,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public bool IsIndexer { get; set; } public bool ReturnTypeIsRefReadOnly => false; public IReadOnlyList Parameters { get; set; } + + public override string ToString() => + "FakeProperty " + ReturnType + " " + DeclaringType.Name + "." + Name + + (Parameters.Count == 0 + ? "" + : "[" + string.Join(", ", Parameters) + "]") + + " { " + + (CanGet ? "get; " : "") + + (CanSet ? "set; " : "") + + "}"; } sealed class FakeEvent : FakeMember, IEvent