diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs index 9fb7bc2b3..8ecde801a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs @@ -23,13 +23,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } - private class CtorTarget - { - public CtorTarget(dynamic d, int i) - { - } - } - private struct MyValueType { private readonly dynamic _getOnlyProperty; @@ -384,57 +377,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { } - private static dynamic M5(dynamic d, int i) - { - return null; - } - - private static void M6(dynamic d, int i) - { - } - #if CS60 - // #3704: the call target of a dynamic member access on a static type is typeof(DynamicTests). - // The array is loaded into a temporary that survives as its own statement, which strands the - // typeof between the two, so it cannot reach the call site by ordinary inlining. - private static void StaticTargetBehindSurvivingTemporary(dynamic d) - { -#if EXPECTED_OUTPUT - byte[] data = GetData(); - DynamicTests.M4(d, (data != null) ? data.Length : 0); -#else - DynamicTests.M4(d, GetData()?.Length ?? 0); -#endif - } - - private static dynamic StaticTargetResultUsed(dynamic d) - { -#if EXPECTED_OUTPUT - byte[] data = GetData(); - return DynamicTests.M5(d, (data != null) ? data.Length : 0); -#else - return DynamicTests.M5(d, GetData()?.Length ?? 0); -#endif - } - - private static void StaticTargetWithTypeArguments(dynamic d) + // #3704: the call target of a dynamic member access on a static type is + // typeof(DynamicTests), which has to reach the call site. + private static void StaticTargetOnDynamicCall(dynamic d) { -#if EXPECTED_OUTPUT - byte[] data = GetData(); - DynamicTests.M6(d, (data != null) ? data.Length : 0); -#else - DynamicTests.M6(d, GetData()?.Length ?? 0); -#endif - } - - private static void StaticCtorBehindSurvivingTemporary(dynamic d) - { -#if EXPECTED_OUTPUT - byte[] data = GetData(); - new CtorTarget(d, (data != null) ? data.Length : 0); -#else - new CtorTarget(d, GetData()?.Length ?? 0); -#endif + DynamicTests.M4(d, GetData()?.Length ?? 0); } #endif diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs index c630c5d4f..b2c149034 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs @@ -320,6 +320,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty Console.WriteLine(setsOfNumbers?[1]?[1].ToString() == null); } + private static byte[] GetBytes() + { + return null; + } + + private static void ArrayLengthWithFallback() + { + Console.WriteLine(GetBytes()?.Length ?? 0); + Console.WriteLine(GetBytes()?.LongLength ?? 0); + } + private static dynamic DynamicNullProp(dynamic a) { return a?.b.c(1)?.d[10]; diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 953e46c56..9d7a329fe 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -4601,10 +4601,10 @@ namespace ICSharpCode.Decompiler.CSharp protected internal override TranslatedExpression VisitDynamicInvokeMemberInstruction(DynamicInvokeMemberInstruction inst, TranslationContext context) { Expression targetExpr; - var target = inst.StaticTargetType is IType staticTargetType - ? new TypeReferenceExpression(ConvertType(staticTargetType)) + var target = inst.StaticTargetType != null + ? new TypeReferenceExpression(ConvertType(inst.StaticTargetType)) .WithoutILInstruction() - .WithRR(new TypeResolveResult(staticTargetType)) + .WithRR(new TypeResolveResult(inst.StaticTargetType)) : TranslateDynamicTarget(inst.Arguments[0], inst.ArgumentInfo[0]); if (inst.BinderFlags.HasFlag(CSharpBinderFlags.InvokeSimpleName) && target.Expression is ThisReferenceExpression) { diff --git a/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs b/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs index 459cfef76..ca8da349a 100644 --- a/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs +++ b/ICSharpCode.Decompiler/IL/ILTypeExtensions.cs @@ -287,6 +287,12 @@ namespace ICSharpCode.Decompiler.IL default: return SpecialType.UnknownType; } + case LdLen ldLen: + if (compilation == null) + return SpecialType.UnknownType; + // Mirrors ExpressionBuilder.VisitLdLen, which picks Array.Length or + // Array.LongLength based on the result type alone. + return compilation.FindType(ldLen.ResultType == StackType.I4 ? KnownTypeCode.Int32 : KnownTypeCode.Int64); case DefaultValue defaultValue: return defaultValue.Type; case ILFunction func when func.DelegateType != null: