Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions ICSharpCode.BamlDecompiler/Rewrite/MarkupExtensionRewritePass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,9 @@ bool CanInlineExt(XamlContext ctx, XElement ctxElement)
var type = ctxElement.Annotation<XamlType>();
if (type != null && type.ResolvedType != null)
{
var typeDef = type.ResolvedType.GetDefinition()?.DirectBaseTypes.FirstOrDefault();
bool isExt = false;
while (typeDef != null)
{
if (typeDef.FullName == "System.Windows.Markup.MarkupExtension")
{
isExt = true;
break;
}
typeDef = typeDef.DirectBaseTypes.FirstOrDefault();
}
var typeDef = type.ResolvedType.GetDefinition();
bool isExt = typeDef != null && typeDef.GetNonInterfaceBaseTypes()
.Any(t => t != typeDef && t.FullName == "System.Windows.Markup.MarkupExtension");
if (!isExt)
return false;
}
Expand Down Expand Up @@ -209,4 +201,4 @@ XamlExtension InlineExtension(XamlContext ctx, XElement ctxElement)
return ext;
}
}
}
}
9 changes: 3 additions & 6 deletions ICSharpCode.BamlDecompiler/Xaml/XamlProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,11 @@ public bool IsAttachedTo(XamlType type)
}

var declType = ResolvedMember.DeclaringType;
var t = type.ResolvedType;

do
foreach (var t in type.ResolvedType.GetNonInterfaceBaseTypes())
{
if (t.FullName == declType.FullName && t.TypeParameterCount == declType.TypeParameterCount)
return false;
t = t.DirectBaseTypes.FirstOrDefault();
} while (t != null);
}
return true;
}

Expand Down Expand Up @@ -123,4 +120,4 @@ public XName ToXName(XamlContext ctx, XElement parent, bool isFullName = true)

public override string ToString() => PropertyName;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,12 @@
<None Include="TestCases\ILPretty\InstanceOperatorCall.il" />
<Compile Remove="TestCases\ILPretty\EnumArithmeticOutOfRange.cs" />
<None Include="TestCases\ILPretty\EnumArithmeticOutOfRange.cs" />
<Compile Remove="TestCases\ILPretty\EmptyBodies.cs" />
<None Include="TestCases\ILPretty\EmptyBodies.cs" />
<Compile Remove="TestCases\ILPretty\TruncatedAccessorBody.cs" />
<Compile Remove="TestCases\ILPretty\EmptyBodies.cs" />
<None Include="TestCases\ILPretty\EmptyBodies.cs" />
<Compile Remove="TestCases\ILPretty\CyclicBaseClass.cs" />
<None Include="TestCases\ILPretty\CyclicBaseClass.cs" />
<None Include="TestCases\ILPretty\CyclicBaseClass.il" />
<Compile Remove="TestCases\ILPretty\TruncatedAccessorBody.cs" />
<None Include="TestCases\ILPretty\TruncatedAccessorBody.cs" />
<Compile Remove="TestCases\ILPretty\SealedRecordProtectedCopyCtor.cs" />
<None Include="TestCases\ILPretty\SealedRecordProtectedCopyCtor.cs" />
Expand Down
6 changes: 6 additions & 0 deletions ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,12 @@ public async Task EmptyBodies()
await Run();
}

[Test]
public async Task CyclicBaseClass()
{
await Run();
}

[Test]
public async Task SealedRecordProtectedCopyCtor()
{
Expand Down
45 changes: 45 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CyclicBaseClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
namespace CyclicBaseClass
{
public abstract class Expanding<T> : Expanding<Expanding<T>>
{
}

public static class Extensions
{
public static void Deconstruct(this SelfDerived value, out int a, out int b)
{
a = 1;
b = 2;
}

public static void Deconstruct<T>(this Expanding<T> value, out int a, out int b)
{
a = 1;
b = 2;
}
}

public static class NestedDeconstruction
{
public static int Sum(Pair<SelfDerived> pair)
{
var (num4, (num5, num6)) = pair;
return num4 + num5 + num6;
}

public static int Sum(Pair<Expanding<int>> pair)
{
var (num4, (num5, num6)) = pair;
return num4 + num5 + num6;
}
}

public abstract class Pair<T>
{
public abstract void Deconstruct(out int first, out T second);
}

public abstract class SelfDerived : SelfDerived
{
}
}
163 changes: 163 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CyclicBaseClass.il
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89)
.ver 4:0:0:0
}

.assembly CyclicBaseClass
{
.hash algorithm 0x00008004
.ver 1:0:0:0
}

.module CyclicBaseClass.dll

.class public auto ansi abstract beforefieldinit CyclicBaseClass.SelfDerived
extends CyclicBaseClass.SelfDerived
{
}

.class public auto ansi abstract beforefieldinit CyclicBaseClass.Expanding`1<T>
extends class CyclicBaseClass.Expanding`1<class CyclicBaseClass.Expanding`1<!T>>
{
}

.class public auto ansi abstract sealed beforefieldinit CyclicBaseClass.Extensions
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
.method public hidebysig static
void Deconstruct (
class CyclicBaseClass.SelfDerived 'value',
[out] int32& a,
[out] int32& b
) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
.maxstack 8
ldarg.1
ldc.i4.1
stind.i4
ldarg.2
ldc.i4.2
stind.i4
ret
}

.method public hidebysig static
void Deconstruct<T> (
class CyclicBaseClass.Expanding`1<!!T> 'value',
[out] int32& a,
[out] int32& b
) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
.maxstack 8
ldarg.1
ldc.i4.1
stind.i4
ldarg.2
ldc.i4.2
stind.i4
ret
}
}

.class public auto ansi abstract beforefieldinit CyclicBaseClass.Pair`1<T>
extends [mscorlib]System.Object
{
.method public hidebysig newslot abstract virtual
instance void Deconstruct (
[out] int32& first,
[out] !T& second
) cil managed
{
}

.method family hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}

.class public auto ansi abstract sealed beforefieldinit CyclicBaseClass.NestedDeconstruction
extends [mscorlib]System.Object
{
.method public hidebysig static
int32 Sum (
class CyclicBaseClass.Pair`1<class CyclicBaseClass.SelfDerived> pair
) cil managed
{
.maxstack 3
.locals init (
[0] int32,
[1] int32,
[2] int32,
[3] class CyclicBaseClass.SelfDerived,
[4] int32,
[5] int32
)
ldarg.0
ldloca.s 2
ldloca.s 3
callvirt instance void class CyclicBaseClass.Pair`1<class CyclicBaseClass.SelfDerived>::Deconstruct(int32&, !0&)
ldloc.3
ldloca.s 4
ldloca.s 5
call void CyclicBaseClass.Extensions::Deconstruct(class CyclicBaseClass.SelfDerived, int32&, int32&)
ldloc.2
ldloc.s 4
stloc.0
ldloc.s 5
stloc.1
ldloc.0
add
ldloc.1
add
ret
}

.method public hidebysig static
int32 Sum (
class CyclicBaseClass.Pair`1<class CyclicBaseClass.Expanding`1<int32>> pair
) cil managed
{
.maxstack 3
.locals init (
[0] int32,
[1] int32,
[2] int32,
[3] class CyclicBaseClass.Expanding`1<int32>,
[4] int32,
[5] int32
)
ldarg.0
ldloca.s 2
ldloca.s 3
callvirt instance void class CyclicBaseClass.Pair`1<class CyclicBaseClass.Expanding`1<int32>>::Deconstruct(int32&, !0&)
ldloc.3
ldloca.s 4
ldloca.s 5
call void CyclicBaseClass.Extensions::Deconstruct<int32>(class CyclicBaseClass.Expanding`1<!!0>, int32&, int32&)
ldloc.2
ldloc.s 4
stloc.0
ldloc.s 5
stloc.1
ldloc.0
add
ldloc.1
add
ret
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -630,9 +630,12 @@ static bool IsReceiverReference(ILInstruction target, ILVariable receiver)
static bool BindsOnElementType(IMethod method, IType elementType)
{
int outParamCount = method.Parameters.Count - (method.IsStatic ? 1 : 0);
IType type = elementType;
while (type != null)
// The element type followed by its base classes, most derived first. The base class is
// metadata and may be cyclic, which GetNonInterfaceBaseTypes() tolerates.
foreach (IType type in elementType.GetNonInterfaceBaseTypes().Reverse())
{
if (type != elementType && type.Kind != TypeKind.Class)
continue;
if (!method.IsStatic && NormalizeTypeVisitor.TypeErasure.EquivalentTypes(type, method.DeclaringType))
return true;
if (type.GetMethods(m => m.Name == "Deconstruct", GetMemberOptions.IgnoreInheritedMembers)
Expand All @@ -643,7 +646,6 @@ static bool BindsOnElementType(IMethod method, IType elementType)
// method (and wins over a called extension method).
return false;
}
type = type.DirectBaseTypes.FirstOrDefault(t => t.Kind == TypeKind.Class)!;
}
// The chain ended without seeing the declaring type, so an instance method's
// binding cannot be verified. An extension method is reached by its receiver
Expand Down
Loading