Browse Source

Add tests for ExtensionEncodingV1 and ExtensionEncodingV2.

pull/3606/head
Siegfried Pammer 2 months ago
parent
commit
f6c763e7bb
  1. 2
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 4
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 16
      ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
  4. 38
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV1.cs
  5. 253
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV1.il
  6. 33
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV2.cs
  7. 328
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV2.il
  8. 39
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  9. 84
      ICSharpCode.Decompiler/TypeSystem/ExtensionInfo.cs

2
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -133,7 +133,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -133,7 +133,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
await vswhereToolset.Fetch().ConfigureAwait(false);
await RefAssembliesToolset.Fetch("5.0.0", sourcePath: "ref/net5.0").ConfigureAwait(false);
await RefAssembliesToolset.Fetch("10.0.0-preview.4.25258.110", sourcePath: "ref/net10.0").ConfigureAwait(false);
await RefAssembliesToolset.Fetch("10.0.0-rc.2.25502.107", sourcePath: "ref/net10.0").ConfigureAwait(false);
#if DEBUG

4
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -96,6 +96,8 @@ @@ -96,6 +96,8 @@
<None Include="TestCases\Disassembler\Pretty\InterfaceImplAttributes.il" />
<None Include="TestCases\Disassembler\Pretty\SortMembers.expected.il" />
<None Include="TestCases\Disassembler\Pretty\SortMembers.il" />
<None Include="TestCases\ILPretty\ExtensionEncodingV2.il" />
<None Include="testcases\ilpretty\ExtensionEncodingV1.il" />
<None Include="TestCases\ILPretty\GuessAccessors.cs" />
<None Include="TestCases\ILPretty\GuessAccessors.il" />
<None Include="TestCases\ILPretty\Issue2260SwitchString.il" />
@ -145,6 +147,8 @@ @@ -145,6 +147,8 @@
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
<Compile Include="ProjectDecompiler\WholeProjectDecompilerTests.cs" />
<Compile Include="TestAssemblyResolver.cs" />
<Compile Include="TestCases\ILPretty\ExtensionEncodingV2.cs" />
<Compile Include="TestCases\ILPretty\ExtensionEncodingV1.cs" />
<Compile Include="TestCases\ILPretty\Issue3344CkFinite.cs" />
<Compile Include="TestCases\ILPretty\Issue3421.cs" />
<Compile Include="TestCases\ILPretty\Issue3465.cs" />

16
ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

@ -323,6 +323,22 @@ namespace ICSharpCode.Decompiler.Tests @@ -323,6 +323,22 @@ namespace ICSharpCode.Decompiler.Tests
await Run();
}
[Test]
public async Task ExtensionEncodingV1()
{
// uses Microsoft.Net.Compilers.Toolset 5.0.0-2.25380.108
// see ExtensionEncodingV1.il for details
await Run();
}
[Test]
public async Task ExtensionEncodingV2()
{
// uses Microsoft.Net.Compilers.Toolset 5.0.0-2.25451.107
// see ExtensionEncodingV2.il for details
await Run();
}
async Task Run([CallerMemberName] string testName = null, DecompilerSettings settings = null,
AssemblerOptions assemblerOptions = AssemblerOptions.Library)
{

38
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV1.cs

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
{
internal static class ExtensionPropertiesV1
{
extension<T>(ICollection<T> collection) where T : notnull
{
public bool IsEmpty => collection.Count == 0;
public int Test {
get {
return 42;
}
set {
}
}
public void AddIfNotNull(T item)
{
if (item != null)
{
collection.Add(item);
}
}
public T2 Cast<T2>(int index) where T2 : T
{
return (T2)(object)collection.ElementAt(index);
}
public static void StaticExtension()
{
}
}
}
}

253
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV1.il

@ -0,0 +1,253 @@ @@ -0,0 +1,253 @@
// To extend use:
// see https://lab.razor.fyi/#fVHNbhMxEFYRqrBP0CcYbpsDVlioVDU_UrSNUBCqImVPnHC8k8TgtRd7tiSqcuMh-gbceQBeihdA66bJNlK5WDPzfTPffGP-65TzqXdLL0uhwtndaR20XcJsEwjLHm9nInPGoCLtbBAf0KLX6j-MSVnWJOcGjzhXWi6tC6RVeBoRmStwZKXZBH1M-6Tt96NSvvIoC22XT9VFLsO30OPcyhJDJRXCJJutpK8aIXGFypWVNuhFjoFCfDMZMIipR6INv-VMW0JvpYFAkrQCZWQIMF4T2qCdnXpXoSeNgbNbzhg-AP18mEwOl-nnQ1D7rAM_VugRcrgE68jWxnAW-1lVz41WMHfOwCSMy4o2MGj3iszVlmAwgG6Ptzq0JWgMQBzDlvgQMY9Uewvv017Mt_ENezzm2_aoG6cLGBXFZHHt6Lo2JslBE5adhnPfpBeQNCV4PYBm_QjtMNZadlQUkddpaT_SylPIZKB-ng6TxoK2Ba7390nhEvKD6s5JkqedxM2_oqJOS2tssERLI0ruh0TJR2K7P4z-ZjHef2RyMNcsueVsy7f87NW56Irum1Sk5-8uuuJt9-LjM20-sxd3P__-_rN4-fzLyfrkHw
// created using https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-tools/NuGet/Microsoft.Net.Compilers.Toolset/overview/5.0.0-2.25380.108
.class private auto ansi abstract sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV1
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
// Nested Types
.class nested public auto ansi sealed specialname beforefieldinit '<>E__0`1'<T>
extends [System.Runtime]System.Object
{
// Methods
.method private hidebysig specialname static
void '<Extension>$' (
class [System.Runtime]System.Collections.Generic.ICollection`1<!T> collection
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x209d
// Header size: 1
// Code size: 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method '<>E__0`1'::'<Extension>$'
.method public hidebysig specialname
instance bool get_IsEmpty () cil managed
{
// Method begins at RVA 0x209f
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<>E__0`1'::get_IsEmpty
.method public hidebysig specialname
instance int32 get_Test () cil managed
{
// Method begins at RVA 0x209f
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<>E__0`1'::get_Test
.method public hidebysig specialname
instance void set_Test (
int32 'value'
) cil managed
{
// Method begins at RVA 0x209f
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<>E__0`1'::set_Test
.method public hidebysig
instance void AddIfNotNull (
!T item
) cil managed
{
// Method begins at RVA 0x209f
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<>E__0`1'::AddIfNotNull
.method public hidebysig
instance !!T2 Cast<(!T) T2> (
int32 index
) cil managed
{
.param type T2
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
// Method begins at RVA 0x209f
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<>E__0`1'::Cast
.method public hidebysig static
void StaticExtension () cil managed
{
// Method begins at RVA 0x209f
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<>E__0`1'::StaticExtension
// Properties
.property instance bool IsEmpty()
{
.get instance bool ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV1/'<>E__0`1'::get_IsEmpty()
}
.property instance int32 Test()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV1/'<>E__0`1'::get_Test()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV1/'<>E__0`1'::set_Test(int32)
}
} // end of class <>E__0`1
// Methods
.method public hidebysig static
bool get_IsEmpty<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection
) cil managed
{
// Method begins at RVA 0x2050
// Header size: 1
// Code size: 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance int32 class [System.Runtime]System.Collections.Generic.ICollection`1<!!T>::get_Count()
IL_0006: ldc.i4.0
IL_0007: ceq
IL_0009: ret
} // end of method ExtensionProperties::get_IsEmpty
.method public hidebysig static
int32 get_Test<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection
) cil managed
{
// Method begins at RVA 0x205b
// Header size: 1
// Code size: 4 (0x4)
.maxstack 8
IL_0000: nop
IL_0001: ldc.i4.s 42
IL_0003: ret
} // end of method ExtensionProperties::get_Test
.method public hidebysig static
void set_Test<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection,
int32 'value'
) cil managed
{
// Method begins at RVA 0x2060
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method ExtensionProperties::set_Test
.method public hidebysig static
void AddIfNotNull<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection,
!!T item
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2064
// Header size: 12
// Code size: 25 (0x19)
.maxstack 2
.locals init (
[0] bool
)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: box !!T
IL_0007: ldnull
IL_0008: cgt.un
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: brfalse.s IL_0018
IL_000e: nop
IL_000f: ldarg.0
IL_0010: ldarg.1
IL_0011: callvirt instance void class [System.Runtime]System.Collections.Generic.ICollection`1<!!T>::Add(!0)
IL_0016: nop
IL_0017: nop
IL_0018: ret
} // end of method ExtensionProperties::AddIfNotNull
.method public hidebysig static
!!T2 Cast<T, (!!T) T2> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection,
int32 index
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x2089
// Header size: 1
// Code size: 19 (0x13)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call !!0 [System.Linq]System.Linq.Enumerable::ElementAt<!!T>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>, int32)
IL_0008: box !!T
IL_000d: unbox.any !!T2
IL_0012: ret
} // end of method ExtensionProperties::Cast
.method public hidebysig static
void StaticExtension<T> () cil managed
{
// Method begins at RVA 0x2060
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method ExtensionProperties::StaticExtension
} // end of class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV1

33
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV2.cs

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
{
internal static class ExtensionPropertiesV2
{
extension<T>(ICollection<T> collection) where T : notnull
{
public bool IsEmpty => collection.Count == 0;
public int Test {
get {
return 42;
}
set {
}
}
public void AddIfNotNull(T item)
{
if (item != null)
{
collection.Add(item);
}
}
public T2 Cast<T2>(int index) where T2 : T
{
return (T2)(object)collection.ElementAt(index);
}
public static void StaticExtension()
{
}
}
}
}

328
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ExtensionEncodingV2.il

@ -0,0 +1,328 @@ @@ -0,0 +1,328 @@
// To extend use:
// see https://lab.razor.fyi/#fVHBbtNAEFUQArwn6BcMPdkSrFyrFVKbVIrcgIKqKKKrHkBIbOyps3S9a3bHtFEViQvfwy9w4Qf4D66ckd00dSOVy2pn3nvz5u2y748ZmzpbOFnyzG_9fVR7ZQo4WXjC8oB1K55arTEjZY3nb9CgU9l_GOOyrEnONG5wjpQsjPWkMn8_wlOb49BIvfBqk3aszJeNlpg7lLkyxX19LqQ_3xz0rjakSuSn6LyyppWzD9J7LGd6sQ9CugLptZMlXlh3Hm7zyUik1uGwql6sRIOdmMfb0UfGjCzRVzJDGKcnc-mqJgI_wsyWldLouEBPvj1T6dHz8fHUIdGCXbFAGUJnpAZPklQGmZbew-iS0DQuU2crdKTQnyYsuGJBgDdQXxyG49t374tDyNZVBBdzdAgC9sFYMrXWLGj1QVXPtMpgZq2GsR-VFS1g0NXy1NaGYDCA-IB1FMoQNCGgHRMUeHMLHFLtDOwmB229bE-_xtt62R311aochnk-PptYmtRahwIUYRk1nGuROoOwacHzATTrt9AKCzrLDvO85UUd7zteIoFUeuqL5DBsIiiT4-X6fRLYB3HrukoSiiQK7ewzZhR1vEYaSzQ0pPB6SGt5x2z1i22-k_a-_srwNlyz5JIFS7ZkW8_2eMzjlwlP9nb3dvhO_OrtA6XfB09-__n14-fZ04efevPeZe9br_cP
// created using https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-tools/NuGet/Microsoft.Net.Compilers.Toolset/overview/5.0.0-2.25451.107
.assembly TestProject
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = {
}
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = {
int32(8)
}
.custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = {
property bool WrapNonExceptionThrows = bool(true)
}
.custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = {
int32(263)
}
.custom instance void [System.Runtime]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = {
string('.NETCoreApp,Version=10.0')
}
.permissionset reqmin = {
[System.Runtime]System.Security.Permissions.SecurityPermissionAttribute = {
property bool SkipVerification = bool(true)
}
}
.hash algorithm 0x00008004 // SHA1
.ver 0:0:0:0
}
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class private auto ansi abstract sealed beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV2
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = {
uint8(1)
}
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = {
uint8(0)
}
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = {
}
// Nested Types
.class nested public auto ansi sealed specialname '<G>$847CB318C385471B1F4E7BD0A197DBCA'<$T0>
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = {
}
// Nested Types
.class nested public auto ansi abstract sealed specialname '<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B'<T>
extends [System.Runtime]System.Object
{
// Methods
.method public hidebysig specialname static
void '<Extension>$' (
class [System.Runtime]System.Collections.Generic.ICollection`1<!T> collection
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = {
}
// Method begins at RVA 0x20a0
// Header size: 1
// Code size: 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method '<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B'::'<Extension>$'
} // end of class <M>$6A79ECC07A7731C57E8EB4E3D9C8B38B
// Methods
.method public hidebysig specialname
instance bool get_IsEmpty () cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
// Method begins at RVA 0x209d
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<G>$847CB318C385471B1F4E7BD0A197DBCA'::get_IsEmpty
.method public hidebysig specialname
instance int32 get_Test () cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
// Method begins at RVA 0x209d
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<G>$847CB318C385471B1F4E7BD0A197DBCA'::get_Test
.method public hidebysig specialname
instance void set_Test (
int32 'value'
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
// Method begins at RVA 0x209d
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<G>$847CB318C385471B1F4E7BD0A197DBCA'::set_Test
.method public hidebysig
instance void AddIfNotNull (
!$T0 item
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
// Method begins at RVA 0x209d
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<G>$847CB318C385471B1F4E7BD0A197DBCA'::AddIfNotNull
.method public hidebysig
instance !!T2 Cast<(!$T0) T2> (
int32 index
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
.param type T2
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = {
uint8(0)
}
// Method begins at RVA 0x209d
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<G>$847CB318C385471B1F4E7BD0A197DBCA'::Cast
.method public hidebysig static
void StaticExtension () cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
// Method begins at RVA 0x209d
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: throw
} // end of method '<G>$847CB318C385471B1F4E7BD0A197DBCA'::StaticExtension
// Properties
.property instance bool IsEmpty()
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
.get instance bool ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV2/'<G>$847CB318C385471B1F4E7BD0A197DBCA'::get_IsEmpty()
}
.property instance int32 Test()
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = {
string('<M>$6A79ECC07A7731C57E8EB4E3D9C8B38B')
}
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV2/'<G>$847CB318C385471B1F4E7BD0A197DBCA'::get_Test()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV2/'<G>$847CB318C385471B1F4E7BD0A197DBCA'::set_Test(int32)
}
} // end of class <G>$847CB318C385471B1F4E7BD0A197DBCA
// Methods
.method public hidebysig static
bool get_IsEmpty<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection
) cil managed
{
// Method begins at RVA 0x2050
// Header size: 1
// Code size: 10 (0xa)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance int32 class [System.Runtime]System.Collections.Generic.ICollection`1<!!T>::get_Count()
IL_0006: ldc.i4.0
IL_0007: ceq
IL_0009: ret
} // end of method ExtensionPropertiesV2::get_IsEmpty
.method public hidebysig static
int32 get_Test<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection
) cil managed
{
// Method begins at RVA 0x205b
// Header size: 1
// Code size: 4 (0x4)
.maxstack 8
IL_0000: nop
IL_0001: ldc.i4.s 42
IL_0003: ret
} // end of method ExtensionPropertiesV2::get_Test
.method public hidebysig static
void set_Test<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection,
int32 'value'
) cil managed
{
// Method begins at RVA 0x2060
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method ExtensionPropertiesV2::set_Test
.method public hidebysig static
void AddIfNotNull<T> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection,
!!T item
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = {
}
// Method begins at RVA 0x2064
// Header size: 12
// Code size: 25 (0x19)
.maxstack 2
.locals init (
[0] bool
)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: box !!T
IL_0007: ldnull
IL_0008: cgt.un
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: brfalse.s IL_0018
IL_000e: nop
IL_000f: ldarg.0
IL_0010: ldarg.1
IL_0011: callvirt instance void class [System.Runtime]System.Collections.Generic.ICollection`1<!!T>::Add(!0)
IL_0016: nop
IL_0017: nop
IL_0018: ret
} // end of method ExtensionPropertiesV2::AddIfNotNull
.method public hidebysig static
!!T2 Cast<T, (!!T) T2> (
class [System.Runtime]System.Collections.Generic.ICollection`1<!!T> collection,
int32 index
) cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = {
}
// Method begins at RVA 0x2089
// Header size: 1
// Code size: 19 (0x13)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call !!0 [System.Linq]System.Linq.Enumerable::ElementAt<!!T>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>, int32)
IL_0008: box !!T
IL_000d: unbox.any !!T2
IL_0012: ret
} // end of method ExtensionPropertiesV2::Cast
.method public hidebysig static
void StaticExtension<T> () cil managed
{
// Method begins at RVA 0x2060
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method ExtensionPropertiesV2::StaticExtension
} // end of class ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ExtensionPropertiesV2
// references
.assembly extern System.Runtime
{
.publickeytoken = (
b0 3f 5f 7f 11 d5 0a 3a
)
.ver 10:0:0:0
}
.assembly extern System.Linq
{
.publickeytoken = (
b0 3f 5f 7f 11 d5 0a 3a
)
.ver 10:0:0:0
}

39
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1367,13 +1367,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1367,13 +1367,16 @@ namespace ICSharpCode.Decompiler.CSharp
foreach (var group in typeDef.ExtensionInfo?.GetGroups() ?? [])
{
var ext = new ExtensionDeclaration();
ext.TypeParameters.AddRange(group.Key.DeclaringTypeDefinition.TypeParameters.Select(tp => typeSystemAstBuilder.ConvertTypeParameter(tp)));
ext.ReceiverParameters.Add(typeSystemAstBuilder.ConvertParameter(group.Key.Parameters.Single()));
ext.Constraints.AddRange(group.Key.DeclaringTypeDefinition.TypeParameters.Select(c => typeSystemAstBuilder.ConvertTypeParameterConstraint(c)));
ITypeParameter[] typeParameters = group.Key.TypeParameters;
var subst = new TypeParameterSubstitution(typeParameters, null);
ext.TypeParameters.AddRange(typeParameters.Select(tp => typeSystemAstBuilder.ConvertTypeParameter(tp)));
var marker = group.Key.Marker.Specialize(subst);
ext.ReceiverParameters.Add(typeSystemAstBuilder.ConvertParameter(marker.Parameters.Single()));
ext.Constraints.AddRange(typeParameters.Select(c => typeSystemAstBuilder.ConvertTypeParameterConstraint(c)));
foreach (var member in group)
{
IMember extMember = member.ExtensionMember;
IMember extMember = member.ExtensionMember.Specialize(subst);
if (member.ExtensionMember.IsAccessor)
{
extMember = member.ExtensionMember.AccessorOwner;
@ -1508,9 +1511,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1508,9 +1511,15 @@ namespace ICSharpCode.Decompiler.CSharp
return;
}
if (settings.ExtensionMembers && extensionInfo != null && entity is IMethod m && extensionInfo.InfoOfImplementationMember(m).HasValue)
if (settings.ExtensionMembers && extensionInfo != null)
{
return;
switch (entity)
{
case ITypeDefinition td when extensionInfo.IsExtensionGroupingType(td):
return;
case IMethod m when extensionInfo.InfoOfImplementationMember(m).HasValue:
return;
}
}
EntityDeclaration entityDecl;
@ -1584,9 +1593,21 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1584,9 +1593,21 @@ namespace ICSharpCode.Decompiler.CSharp
switch (extMember)
{
case IProperty p:
return DoDecompile(p, decompileRun, decompilationContext.WithCurrentMember(p), info);
var prop = DoDecompile(p, decompileRun, decompilationContext.WithCurrentMember(p), info);
RemoveAttribute(prop, KnownAttribute.ExtensionMarker);
if (p.Getter != null)
{
RemoveAttribute(prop.GetChildByRole(PropertyDeclaration.GetterRole), KnownAttribute.ExtensionMarker);
}
if (p.Setter != null)
{
RemoveAttribute(prop.GetChildByRole(PropertyDeclaration.SetterRole), KnownAttribute.ExtensionMarker);
}
return prop;
case IMethod m:
return DoDecompile(m, decompileRun, decompilationContext.WithCurrentMember(m), info);
var meth = DoDecompile(m, decompileRun, decompilationContext.WithCurrentMember(m), info);
RemoveAttribute(meth, KnownAttribute.ExtensionMarker);
return meth;
}
throw new NotSupportedException($"Extension member {extMember} is not supported for decompilation.");
@ -1762,7 +1783,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1762,7 +1783,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (!method.IsStatic)
parameterOffset = 1; // implementation method has an additional receiver parameter
method = extensionInfo.InfoOfExtensionMember(method).Value.ImplementationMethod;
method = extensionInfo.InfoOfExtensionMember((IMethod)method.MemberDefinition).Value.ImplementationMethod;
}
var methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);

84
ICSharpCode.Decompiler/TypeSystem/ExtensionInfo.cs

@ -20,9 +20,12 @@ @@ -20,9 +20,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.TypeSystem
{
public class ExtensionInfo
@ -59,6 +62,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -59,6 +62,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
IMethod? marker = null;
bool hasMultipleMarkers = false;
List<IMethod> extensionMethods = [];
ITypeParameter[] extensionGroupTypeParameters = extGroup.TypeParameters.ToArray();
// For easier access to accessors we use SRM
foreach (var h in td.GetMethods())
@ -82,7 +86,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -82,7 +86,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (marker == null || hasMultipleMarkers)
return false;
CollectImplementationMethods(extGroup, marker, extensionMethods);
CollectImplementationMethods(extGroup, marker, extensionMethods, extensionGroupTypeParameters);
return true;
}
@ -102,6 +106,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -102,6 +106,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
TypeDefinition td = metadata.GetTypeDefinition((TypeDefinitionHandle)extGroup.MetadataToken);
List<IMethod> extensionMethods = [];
ITypeParameter[] extensionGroupTypeParameters = new ITypeParameter[extGroup.TypeParameterCount];
// For easier access to accessors we use SRM
foreach (var h in td.GetMethods())
@ -121,12 +126,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -121,12 +126,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
extensionMethods.Add(method);
}
CollectImplementationMethods(extGroup, marker, extensionMethods);
CollectImplementationMethods(extGroup, marker, extensionMethods, extensionGroupTypeParameters);
return true;
}
void CollectImplementationMethods(ITypeDefinition extGroup, IMethod marker, List<IMethod> extensionMethods)
void CollectImplementationMethods(ITypeDefinition extGroup, IMethod marker, List<IMethod> extensionMethods, ITypeParameter[] extensionGroupTypeParameters)
{
List<(IMethod extension, IMethod implementation)> implementations = [];
string[] typeParameterNames = new string[extGroup.TypeParameterCount];
foreach (var extension in extensionMethods)
{
int expectedTypeParameterCount = extension.TypeParameters.Count + extGroup.TypeParameterCount;
@ -165,15 +174,62 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -165,15 +174,62 @@ namespace ICSharpCode.Decompiler.TypeSystem
);
}
IMethod? foundImpl = null;
foreach (var impl in extensionContainer.Methods)
{
if (!IsMatchingImplementation(impl))
continue;
var emi = new ExtensionMemberInfo(marker, extension, impl);
extensionMemberMap[extension] = emi;
implementationMemberMap[impl] = emi;
Debug.Assert(foundImpl == null, "Multiple matching implementations found");
foundImpl = impl;
}
Debug.Assert(foundImpl != null, "No matching implementation found");
implementations.Add((extension, foundImpl));
}
foreach (var (extension, implementation) in implementations)
{
for (int i = 0; i < extensionGroupTypeParameters.Length; i++)
{
if (typeParameterNames[i] == null)
{
typeParameterNames[i] = implementation.TypeParameters[i].Name;
}
else if (typeParameterNames[i] != implementation.TypeParameters[i].Name)
{
// TODO: Handle name conflicts properly
typeParameterNames[i] = $"T{i + 1}";
}
}
}
for (int i = 0; i < extensionGroupTypeParameters.Length; i++)
{
var originalTypeParameter = extGroup.TypeParameters[i];
if (extensionGroupTypeParameters[i] == null)
{
extensionGroupTypeParameters[i] = new DefaultTypeParameter(
extGroup, i, typeParameterNames[i],
VarianceModifier.Invariant,
attributes: originalTypeParameter.GetAttributes().ToArray(),
originalTypeParameter.HasValueTypeConstraint,
originalTypeParameter.HasReferenceTypeConstraint,
originalTypeParameter.HasDefaultConstructorConstraint,
originalTypeParameter.TypeConstraints.Select(c => c.Type).ToArray(),
originalTypeParameter.NullabilityConstraint
);
}
}
foreach (var (extension, implementation) in implementations)
{
var info = new ExtensionMemberInfo(marker, extension, implementation, extensionGroupTypeParameters);
this.extensionMemberMap[extension] = info;
this.implementationMemberMap[implementation] = info;
}
}
}
@ -187,13 +243,18 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -187,13 +243,18 @@ namespace ICSharpCode.Decompiler.TypeSystem
return this.implementationMemberMap.TryGetValue(method, out var value) ? value : null;
}
public IEnumerable<IGrouping<IMethod, ExtensionMemberInfo>> GetGroups()
public IEnumerable<IGrouping<(IMethod Marker, ITypeParameter[] TypeParameters), ExtensionMemberInfo>> GetGroups()
{
return this.extensionMemberMap.Values.GroupBy(x => (x.ExtensionMarkerMethod, x.ExtensionGroupingTypeParameters));
}
public bool IsExtensionGroupingType(ITypeDefinition type)
{
return this.extensionMemberMap.Values.GroupBy(x => x.ExtensionMarkerMethod);
return this.extensionMemberMap.Values.Any(x => x.ExtensionGroupingType.Equals(type));
}
}
public readonly struct ExtensionMemberInfo(IMethod marker, IMethod extension, IMethod implementation)
public readonly struct ExtensionMemberInfo(IMethod marker, IMethod extension, IMethod implementation, ITypeParameter[] extensionGroupingTypeParameters)
{
/// <summary>
/// Metadata-only method called '&lt;Extension&gt;$'. Has the C# signature for the extension declaration.
@ -223,6 +284,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -223,6 +284,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
public ITypeDefinition ExtensionGroupingType => ExtensionMember.DeclaringTypeDefinition!;
/// <summary>
/// This is the array of type parameters for the extension declaration.
/// </summary>
public ITypeParameter[] ExtensionGroupingTypeParameters => extensionGroupingTypeParameters;
/// <summary>
/// This class holds the type parameters for the extension declaration with full fidelity of C# constraints.
/// </summary>

Loading…
Cancel
Save