From 349a89c1fac5f075acf3d2bd803307b7248a26d1 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer <siegfriedpammer@gmail.com> Date: Sat, 29 Mar 2025 17:57:43 +0100 Subject: [PATCH] Fix #3436: Duplicate naming of local functions --- .../TestCases/Pretty/DelegateConstruction.cs | 32 ++-- .../TestCases/Pretty/LocalFunctions.cs | 154 +++++++++--------- .../IL/Transforms/AssignVariableNames.cs | 44 +++-- ILSpy/Properties/Resources.resx | 6 +- 4 files changed, 125 insertions(+), 111 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs index d7566dced..8b96d4a6f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs @@ -183,7 +183,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction public interface IM3 { - void M3(); + void M(); } public class BaseClass : IM3 @@ -194,7 +194,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction protected virtual void M2() { } - public virtual void M3() + public virtual void M() { } @@ -209,7 +209,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction protected override void M2() { } - public new void M3() + public new void M() { } @@ -219,30 +219,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction Noop("M1", M1); Noop("M2.base", base.M2); Noop("M2", M2); - Noop("M3.base", base.M3); - Noop("M3.base_virt", ((BaseClass)this).M3); - Noop("M3.base_interface", ((IM3)this).M3); + Noop("M.base", base.M); + Noop("M.base_virt", ((BaseClass)this).M); + Noop("M.base_interface", ((IM3)this).M); #if CS70 - Noop("M3", this.M3); - Noop("M3", M3); + Noop("M", this.M); + Noop("M", M); #if CS80 - static void M3() + static void M() #else - void M3() + void M() #endif { } #else - Noop("M3", M3); + Noop("M", M); #endif } public void Test2() { - Noop("M3.new", new BaseClass().M3); - Noop("M3.new", new SubClass().M3); + Noop("M.new", new BaseClass().M); + Noop("M.new", new SubClass().M); } private void Noop(string name, Action _) @@ -525,7 +525,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction public static void LocalFunctionDelegateReference() { Use(LocalFunction); - Use2<int>(LocalFunction1<int>); + Use2<int>(LocalFunction2<int>); #if CS80 static void LocalFunction() #else @@ -534,9 +534,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction { } #if CS80 - static void LocalFunction1<T>() + static void LocalFunction2<T>() #else - void LocalFunction1<T>() + void LocalFunction2<T>() #endif { } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs index ff29a4351..36c2d340a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs @@ -42,50 +42,50 @@ namespace LocalFunctions for (int i = 0; i < 10; i++) { int i2 = 0; - i2 += NonStaticMethod6<object>(0); + i2 += NonStaticMethod<object>(0); #if CS90 [My] [return: My] - int NonStaticMethod6<[My] T3>([My] int unused) + int NonStaticMethod<[My] T3>([My] int unused) #else - int NonStaticMethod6<T3>(int unused) + int NonStaticMethod<T3>(int unused) #endif { t2 = default(T2); int l = 0; - return NonStaticMethod6_1<T1>() + NonStaticMethod6_1<T2>() + z.GetHashCode(); - int NonStaticMethod6_1<T4>() + return NonStaticMethod2<T1>() + NonStaticMethod2<T2>() + z.GetHashCode(); + int NonStaticMethod2<T4>() { - return i2 + l + NonStaticMethod6<T4>(0) + StaticMethod1<decimal>(); + return i2 + l + NonStaticMethod<T4>(0) + StaticMethod<decimal>(); } } } - return MixedLocalFunction<T1>() + MixedLocalFunction<T2>() + StaticMethod1<decimal>() + StaticMethod1<int>() + NonStaticMethod3() + StaticMethod4<object>(null) + StaticMethod5<T1>(); + return MixedLocalFunction<T1>() + MixedLocalFunction<T2>() + StaticMethod<decimal>() + StaticMethod<int>() + NonStaticMethod3() + StaticMethod4<object>(null) + StaticMethod5<T1>(); int NonStaticMethod3() { return GetHashCode(); } #if CS80 - static int StaticMethod1<T3>() where T3 : struct + static int StaticMethod<T3>() where T3 : struct #else - int StaticMethod1<T3>() where T3 : struct + int StaticMethod<T3>() where T3 : struct #endif { - return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + StaticMethod1<float>() + StaticMethod1_1<T3, DayOfWeek>() + StaticMethod2_RepeatT2<T2, T3, DayOfWeek>(); + return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + StaticMethod<float>() + StaticMethod2<T3, DayOfWeek>() + StaticMethod3<T2, T3, DayOfWeek>(); } #if CS80 - static int StaticMethod1_1<T3, T4>() where T3 : struct where T4 : Enum + static int StaticMethod2<T3, T4>() where T3 : struct where T4 : Enum #else - int StaticMethod1_1<T3, T4>() where T3 : struct where T4 : Enum + int StaticMethod2<T3, T4>() where T3 : struct where T4 : Enum #endif { - return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + typeof(T4).Name.Length + StaticMethod1<float>() + StaticMethod1_1<T3, DayOfWeek>(); + return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + typeof(T4).Name.Length + StaticMethod<float>() + StaticMethod2<T3, DayOfWeek>(); } #pragma warning disable CS8387 #if CS80 - static int StaticMethod2_RepeatT2<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum + static int StaticMethod3<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum #else - int StaticMethod2_RepeatT2<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum + int StaticMethod3<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum #endif #pragma warning restore CS8387 { @@ -106,8 +106,8 @@ namespace LocalFunctions #endif { int k = 0; - return k + NonStaticMethod5_1<T1>(); - int NonStaticMethod5_1<T4>() + return k + NonStaticMethod4<T1>(); + int NonStaticMethod4<T4>() { return k; } @@ -122,20 +122,20 @@ namespace LocalFunctions for (int i = 0; i < 10; i++) { int i2 = 0; - i2 += StaticInvokeAsFunc(NonStaticMethod6<object>); - int NonStaticMethod6<T3>() + i2 += StaticInvokeAsFunc(NonStaticMethod<object>); + int NonStaticMethod<T3>() { t2 = default(T2); int l = 0; - return StaticInvokeAsFunc(NonStaticMethod6_1<T1>) + StaticInvokeAsFunc(NonStaticMethod6_1<T2>) + z.GetHashCode(); - int NonStaticMethod6_1<T4>() + return StaticInvokeAsFunc(NonStaticMethod2<T1>) + StaticInvokeAsFunc(NonStaticMethod2<T2>) + z.GetHashCode(); + int NonStaticMethod2<T4>() { - return i2 + l + StaticInvokeAsFunc(NonStaticMethod6<T4>) + StaticInvokeAsFunc(StaticMethod1<decimal>); + return i2 + l + StaticInvokeAsFunc(NonStaticMethod<T4>) + StaticInvokeAsFunc(StaticMethod<decimal>); } } } Console.WriteLine(t2); - return StaticInvokeAsFunc(MixedLocalFunction2Delegate<T1>) + StaticInvokeAsFunc(MixedLocalFunction2Delegate<T2>) + StaticInvokeAsFunc(StaticMethod1<decimal>) + StaticInvokeAsFunc(StaticMethod1<int>) + StaticInvokeAsFunc(NonStaticMethod3) + StaticInvokeAsFunc(StaticMethod5<T1>) + new Func<object, int>(StaticMethod4<object>)(null) + StaticInvokeAsFunc2<object>(StaticMethod4<object>) + new Func<Func<object, int>, int>(StaticInvokeAsFunc2<object>)(StaticMethod4<object>); + return StaticInvokeAsFunc(MixedLocalFunction2Delegate<T1>) + StaticInvokeAsFunc(MixedLocalFunction2Delegate<T2>) + StaticInvokeAsFunc(StaticMethod<decimal>) + StaticInvokeAsFunc(StaticMethod<int>) + StaticInvokeAsFunc(NonStaticMethod3) + StaticInvokeAsFunc(StaticMethod4<T1>) + new Func<object, int>(StaticMethod5<object>)(null) + StaticInvokeAsFunc2<object>(StaticMethod5<object>) + new Func<Func<object, int>, int>(StaticInvokeAsFunc2<object>)(StaticMethod5<object>); int NonStaticMethod3() { return GetHashCode(); @@ -157,51 +157,51 @@ namespace LocalFunctions return func(default(T)); } #if CS80 - static int StaticMethod1<T3>() where T3 : struct + static int StaticMethod<T3>() where T3 : struct #else - int StaticMethod1<T3>() where T3 : struct + int StaticMethod<T3>() where T3 : struct #endif { - return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + StaticInvokeAsFunc(StaticMethod1<float>) + StaticInvokeAsFunc(StaticMethod1_1<T3, DayOfWeek>) + StaticInvokeAsFunc(StaticMethod2_RepeatT2<T2, T3, DayOfWeek>); + return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + StaticInvokeAsFunc(StaticMethod<float>) + StaticInvokeAsFunc(StaticMethod2<T3, DayOfWeek>) + StaticInvokeAsFunc(StaticMethod3<T2, T3, DayOfWeek>); } #if CS80 - static int StaticMethod1_1<T3, T4>() where T3 : struct where T4 : Enum + static int StaticMethod2<T3, T4>() where T3 : struct where T4 : Enum #else - int StaticMethod1_1<T3, T4>() where T3 : struct where T4 : Enum + int StaticMethod2<T3, T4>() where T3 : struct where T4 : Enum #endif { - return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + typeof(T4).Name.Length + StaticInvokeAsFunc(StaticMethod1<float>) + StaticInvokeAsFunc(StaticMethod1_1<T3, DayOfWeek>); + return typeof(T1).Name.Length + typeof(T2).Name.Length + typeof(T3).Name.Length + typeof(T4).Name.Length + StaticInvokeAsFunc(StaticMethod<float>) + StaticInvokeAsFunc(StaticMethod2<T3, DayOfWeek>); } #pragma warning disable CS8387 #if CS80 - static int StaticMethod2_RepeatT2<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum + static int StaticMethod3<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum #else - int StaticMethod2_RepeatT2<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum + int StaticMethod3<T2, T3, T4>() where T2 : IConvertible where T3 : struct where T4 : Enum #endif #pragma warning restore CS8387 { return typeof(T2).Name.Length; } #if CS80 - static int StaticMethod4<T>(T dd) + static int StaticMethod4<T3>() #else - int StaticMethod4<T>(T dd) + int StaticMethod4<T3>() #endif { - return 0; + int k = 0; + return k + StaticInvokeAsFunc(NonStaticMethod4<T1>); + int NonStaticMethod4<T4>() + { + return k; + } } #if CS80 - static int StaticMethod5<T3>() + static int StaticMethod5<T>(T dd) #else - int StaticMethod5<T3>() + int StaticMethod5<T>(T dd) #endif { - int k = 0; - return k + StaticInvokeAsFunc(NonStaticMethod5_1<T1>); - int NonStaticMethod5_1<T4>() - { - return k; - } + return 0; } } @@ -209,14 +209,14 @@ namespace LocalFunctions { #pragma warning disable CS0219 T2 t2 = default(T2); - Method1<int>(); - void Method1<T3>() + Method<int>(); + void Method<T3>() { t2 = default(T2); T2 t2x = t2; T3 t3 = default(T3); - Method1_1(); - void Method1_1() + Method2(); + void Method2() { t2 = default(T2); t2x = t2; @@ -229,7 +229,7 @@ namespace LocalFunctions public void TestGenericArgs<T2>() where T2 : List<T2> { ZZ<T2>(null); - ZZ2<object>(null); + ZZ3<object>(null); #if CS80 static void Nop<T>(T data) #else @@ -244,25 +244,25 @@ namespace LocalFunctions #endif { Nop<List<T2>>(t3); - ZZ1<T3>(t3); - ZZ3(); - void ZZ3() + ZZ2<T3>(t3); + ZZ4(); + void ZZ4() { Nop<List<T2>>(t3); } } #if CS80 - static void ZZ1<T3>(T3 t3) + static void ZZ2<T3>(T3 t3) #else - void ZZ1<T3>(T3 t3) + void ZZ2<T3>(T3 t3) #endif { Nop<List<T2>>((List<T2>)(object)t3); } #if CS80 - static void ZZ2<T3>(T3 t3) + static void ZZ3<T3>(T3 t3) #else - void ZZ2<T3>(T3 t3) + void ZZ3<T3>(T3 t3) #endif { Nop<List<T2>>((List<T2>)(object)t3); @@ -695,22 +695,22 @@ namespace LocalFunctions public void NestedCapture1() { - Method1(null); + Method(null); #if CS80 - static Action<object> Method1(Action<object> action) + static Action<object> Method(Action<object> action) #else - Action<object> Method1(Action<object> action) + Action<object> Method(Action<object> action) #endif { - return Method1_1; + return Method2; - void Method1_1(object containerBuilder) + void Method2(object containerBuilder) { - Method1_2(containerBuilder); + Method3(containerBuilder); } - void Method1_2(object containerBuilder) + void Method3(object containerBuilder) { action(containerBuilder); } @@ -727,25 +727,25 @@ namespace LocalFunctions #endif { int t0 = 0; - return ZZZ_0(); - int ZZZ_0() + return ZZZ(); + int ZZZ() { t0 = 0; int t2 = t0; - return new Func<int>(ZZZ_0_0)(); - int ZZZ_0_0() + return new Func<int>(ZZZ2)(); + int ZZZ2() { t0 = 0; t2 = 0; - return ZZZ_1(); + return ZZZ3(); } } - int ZZZ_1() + int ZZZ3() { t0 = 0; int t3 = t0; - return new Func<int>(ZZZ_1_0)(); - int ZZZ_1_0() + return new Func<int>(ZZZ4)(); + int ZZZ4() { t0 = 0; t3 = 0; @@ -765,18 +765,18 @@ namespace LocalFunctions #endif { int t0 = 0; - return ZZZ_0(); - int ZZZ_0() + return ZZZ(); + int ZZZ() { t0 = 0; int t2 = t0; return ((Func<int>)delegate { t0 = 0; t2 = 0; - return ZZZ_1(); + return ZZZ2(); })(); } - int ZZZ_1() + int ZZZ2() { t0 = 0; int t3 = t0; @@ -808,18 +808,18 @@ namespace LocalFunctions #endif { int t0 = 0; - return ZZZ_0() + ZZZ_1(); - int ZZZ_0() + return ZZZ() + ZZZ2(); + int ZZZ() { t0 = 0; int t2 = t0; return ((Func<int>)delegate { t0 = 0; t2 = 0; - return ZZZ_1(); + return ZZZ2(); })(); } - int ZZZ_1() + int ZZZ2() { t0 = 0; int t3 = t0; diff --git a/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs index dbe8c5dd4..81dbef08e 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs @@ -512,23 +512,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms // assign names to local functions if (!LocalFunctionDecompiler.ParseLocalFunctionName(function.Name, out _, out var newName) || !IsValidName(newName)) newName = null; - if (newName == null) + string nameWithoutNumber; + int number; + if (!string.IsNullOrEmpty(newName)) { - string nameWithoutNumber = "f"; - if (!context.IsReservedVariableName(nameWithoutNumber, out int currentIndex)) - { - currentIndex = 1; - } - int count = Math.Max(1, currentIndex) + 1; - context.ReserveVariableName(nameWithoutNumber, count); - if (count > 1) - { - newName = nameWithoutNumber + count.ToString(); - } + nameWithoutNumber = SplitName(newName, out number); + } + else + { + nameWithoutNumber = "f"; + number = 1; + } + int count; + if (!context.IsReservedVariableName(nameWithoutNumber, out int currentIndex)) + { + count = 1; + } + else + { + if (currentIndex < number) + count = number; else - { - newName = nameWithoutNumber; - } + count = Math.Max(number, currentIndex) + 1; + } + context.ReserveVariableName(nameWithoutNumber, count); + if (count > 1) + { + newName = nameWithoutNumber + count.ToString(); + } + else + { + newName = nameWithoutNumber; } function.Name = newName; function.ReducedMethod.Name = newName; diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx index 8b6e4ce23..3c23e3ed5 100644 --- a/ILSpy/Properties/Resources.resx +++ b/ILSpy/Properties/Resources.resx @@ -381,6 +381,9 @@ Are you sure you want to continue?</value> <data name="DecompilerSettings.IntroduceLocalFunctions" xml:space="preserve"> <value>Introduce local functions</value> </data> + <data name="DecompilerSettings.IntroducePrivateProtectedAccessibility" xml:space="preserve"> + <value>Introduce 'private protected' accessibility</value> + </data> <data name="DecompilerSettings.IntroduceStaticLocalFunctions" xml:space="preserve"> <value>Introduce static local functions</value> </data> @@ -1108,7 +1111,4 @@ Do you want to continue?</value> <data name="_Window" xml:space="preserve"> <value>_Window</value> </data> - <data name="DecompilerSettings.IntroducePrivateProtectedAccessibility" xml:space="preserve"> - <value>Introduce 'private protected' accessibility</value> - </data> </root> \ No newline at end of file