Browse Source

Fix #3436: Duplicate naming of local functions

pull/3443/head
Siegfried Pammer 4 months ago
parent
commit
349a89c1fa
  1. 32
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  2. 154
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  3. 24
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  4. 6
      ILSpy/Properties/Resources.resx

32
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs

@ -183,7 +183,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction
public interface IM3 public interface IM3
{ {
void M3(); void M();
} }
public class BaseClass : IM3 public class BaseClass : IM3
@ -194,7 +194,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction
protected virtual void M2() 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() 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("M1", M1);
Noop("M2.base", base.M2); Noop("M2.base", base.M2);
Noop("M2", M2); Noop("M2", M2);
Noop("M3.base", base.M3); Noop("M.base", base.M);
Noop("M3.base_virt", ((BaseClass)this).M3); Noop("M.base_virt", ((BaseClass)this).M);
Noop("M3.base_interface", ((IM3)this).M3); Noop("M.base_interface", ((IM3)this).M);
#if CS70 #if CS70
Noop("M3", this.M3); Noop("M", this.M);
Noop("M3", M3); Noop("M", M);
#if CS80 #if CS80
static void M3() static void M()
#else #else
void M3() void M()
#endif #endif
{ {
} }
#else #else
Noop("M3", M3); Noop("M", M);
#endif #endif
} }
public void Test2() public void Test2()
{ {
Noop("M3.new", new BaseClass().M3); Noop("M.new", new BaseClass().M);
Noop("M3.new", new SubClass().M3); Noop("M.new", new SubClass().M);
} }
private void Noop(string name, Action _) private void Noop(string name, Action _)
@ -525,7 +525,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction
public static void LocalFunctionDelegateReference() public static void LocalFunctionDelegateReference()
{ {
Use(LocalFunction); Use(LocalFunction);
Use2<int>(LocalFunction1<int>); Use2<int>(LocalFunction2<int>);
#if CS80 #if CS80
static void LocalFunction() static void LocalFunction()
#else #else
@ -534,9 +534,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction
{ {
} }
#if CS80 #if CS80
static void LocalFunction1<T>() static void LocalFunction2<T>()
#else #else
void LocalFunction1<T>() void LocalFunction2<T>()
#endif #endif
{ {
} }

154
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -42,50 +42,50 @@ namespace LocalFunctions
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
int i2 = 0; int i2 = 0;
i2 += NonStaticMethod6<object>(0); i2 += NonStaticMethod<object>(0);
#if CS90 #if CS90
[My] [My]
[return: My] [return: My]
int NonStaticMethod6<[My] T3>([My] int unused) int NonStaticMethod<[My] T3>([My] int unused)
#else #else
int NonStaticMethod6<T3>(int unused) int NonStaticMethod<T3>(int unused)
#endif #endif
{ {
t2 = default(T2); t2 = default(T2);
int l = 0; int l = 0;
return NonStaticMethod6_1<T1>() + NonStaticMethod6_1<T2>() + z.GetHashCode(); return NonStaticMethod2<T1>() + NonStaticMethod2<T2>() + z.GetHashCode();
int NonStaticMethod6_1<T4>() 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() int NonStaticMethod3()
{ {
return GetHashCode(); return GetHashCode();
} }
#if CS80 #if CS80
static int StaticMethod1<T3>() where T3 : struct static int StaticMethod<T3>() where T3 : struct
#else #else
int StaticMethod1<T3>() where T3 : struct int StaticMethod<T3>() where T3 : struct
#endif #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 #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 #else
int StaticMethod1_1<T3, T4>() where T3 : struct where T4 : Enum int StaticMethod2<T3, T4>() where T3 : struct where T4 : Enum
#endif #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 #pragma warning disable CS8387
#if CS80 #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 #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 #endif
#pragma warning restore CS8387 #pragma warning restore CS8387
{ {
@ -106,8 +106,8 @@ namespace LocalFunctions
#endif #endif
{ {
int k = 0; int k = 0;
return k + NonStaticMethod5_1<T1>(); return k + NonStaticMethod4<T1>();
int NonStaticMethod5_1<T4>() int NonStaticMethod4<T4>()
{ {
return k; return k;
} }
@ -122,20 +122,20 @@ namespace LocalFunctions
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
int i2 = 0; int i2 = 0;
i2 += StaticInvokeAsFunc(NonStaticMethod6<object>); i2 += StaticInvokeAsFunc(NonStaticMethod<object>);
int NonStaticMethod6<T3>() int NonStaticMethod<T3>()
{ {
t2 = default(T2); t2 = default(T2);
int l = 0; int l = 0;
return StaticInvokeAsFunc(NonStaticMethod6_1<T1>) + StaticInvokeAsFunc(NonStaticMethod6_1<T2>) + z.GetHashCode(); return StaticInvokeAsFunc(NonStaticMethod2<T1>) + StaticInvokeAsFunc(NonStaticMethod2<T2>) + z.GetHashCode();
int NonStaticMethod6_1<T4>() int NonStaticMethod2<T4>()
{ {
return i2 + l + StaticInvokeAsFunc(NonStaticMethod6<T4>) + StaticInvokeAsFunc(StaticMethod1<decimal>); return i2 + l + StaticInvokeAsFunc(NonStaticMethod<T4>) + StaticInvokeAsFunc(StaticMethod<decimal>);
} }
} }
} }
Console.WriteLine(t2); 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() int NonStaticMethod3()
{ {
return GetHashCode(); return GetHashCode();
@ -157,51 +157,51 @@ namespace LocalFunctions
return func(default(T)); return func(default(T));
} }
#if CS80 #if CS80
static int StaticMethod1<T3>() where T3 : struct static int StaticMethod<T3>() where T3 : struct
#else #else
int StaticMethod1<T3>() where T3 : struct int StaticMethod<T3>() where T3 : struct
#endif #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 #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 #else
int StaticMethod1_1<T3, T4>() where T3 : struct where T4 : Enum int StaticMethod2<T3, T4>() where T3 : struct where T4 : Enum
#endif #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 #pragma warning disable CS8387
#if CS80 #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 #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 #endif
#pragma warning restore CS8387 #pragma warning restore CS8387
{ {
return typeof(T2).Name.Length; return typeof(T2).Name.Length;
} }
#if CS80 #if CS80
static int StaticMethod4<T>(T dd) static int StaticMethod4<T3>()
#else #else
int StaticMethod4<T>(T dd) int StaticMethod4<T3>()
#endif #endif
{ {
return 0; int k = 0;
return k + StaticInvokeAsFunc(NonStaticMethod4<T1>);
int NonStaticMethod4<T4>()
{
return k;
}
} }
#if CS80 #if CS80
static int StaticMethod5<T3>() static int StaticMethod5<T>(T dd)
#else #else
int StaticMethod5<T3>() int StaticMethod5<T>(T dd)
#endif #endif
{ {
int k = 0; return 0;
return k + StaticInvokeAsFunc(NonStaticMethod5_1<T1>);
int NonStaticMethod5_1<T4>()
{
return k;
}
} }
} }
@ -209,14 +209,14 @@ namespace LocalFunctions
{ {
#pragma warning disable CS0219 #pragma warning disable CS0219
T2 t2 = default(T2); T2 t2 = default(T2);
Method1<int>(); Method<int>();
void Method1<T3>() void Method<T3>()
{ {
t2 = default(T2); t2 = default(T2);
T2 t2x = t2; T2 t2x = t2;
T3 t3 = default(T3); T3 t3 = default(T3);
Method1_1(); Method2();
void Method1_1() void Method2()
{ {
t2 = default(T2); t2 = default(T2);
t2x = t2; t2x = t2;
@ -229,7 +229,7 @@ namespace LocalFunctions
public void TestGenericArgs<T2>() where T2 : List<T2> public void TestGenericArgs<T2>() where T2 : List<T2>
{ {
ZZ<T2>(null); ZZ<T2>(null);
ZZ2<object>(null); ZZ3<object>(null);
#if CS80 #if CS80
static void Nop<T>(T data) static void Nop<T>(T data)
#else #else
@ -244,25 +244,25 @@ namespace LocalFunctions
#endif #endif
{ {
Nop<List<T2>>(t3); Nop<List<T2>>(t3);
ZZ1<T3>(t3); ZZ2<T3>(t3);
ZZ3(); ZZ4();
void ZZ3() void ZZ4()
{ {
Nop<List<T2>>(t3); Nop<List<T2>>(t3);
} }
} }
#if CS80 #if CS80
static void ZZ1<T3>(T3 t3) static void ZZ2<T3>(T3 t3)
#else #else
void ZZ1<T3>(T3 t3) void ZZ2<T3>(T3 t3)
#endif #endif
{ {
Nop<List<T2>>((List<T2>)(object)t3); Nop<List<T2>>((List<T2>)(object)t3);
} }
#if CS80 #if CS80
static void ZZ2<T3>(T3 t3) static void ZZ3<T3>(T3 t3)
#else #else
void ZZ2<T3>(T3 t3) void ZZ3<T3>(T3 t3)
#endif #endif
{ {
Nop<List<T2>>((List<T2>)(object)t3); Nop<List<T2>>((List<T2>)(object)t3);
@ -695,22 +695,22 @@ namespace LocalFunctions
public void NestedCapture1() public void NestedCapture1()
{ {
Method1(null); Method(null);
#if CS80 #if CS80
static Action<object> Method1(Action<object> action) static Action<object> Method(Action<object> action)
#else #else
Action<object> Method1(Action<object> action) Action<object> Method(Action<object> action)
#endif #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); action(containerBuilder);
} }
@ -727,25 +727,25 @@ namespace LocalFunctions
#endif #endif
{ {
int t0 = 0; int t0 = 0;
return ZZZ_0(); return ZZZ();
int ZZZ_0() int ZZZ()
{ {
t0 = 0; t0 = 0;
int t2 = t0; int t2 = t0;
return new Func<int>(ZZZ_0_0)(); return new Func<int>(ZZZ2)();
int ZZZ_0_0() int ZZZ2()
{ {
t0 = 0; t0 = 0;
t2 = 0; t2 = 0;
return ZZZ_1(); return ZZZ3();
} }
} }
int ZZZ_1() int ZZZ3()
{ {
t0 = 0; t0 = 0;
int t3 = t0; int t3 = t0;
return new Func<int>(ZZZ_1_0)(); return new Func<int>(ZZZ4)();
int ZZZ_1_0() int ZZZ4()
{ {
t0 = 0; t0 = 0;
t3 = 0; t3 = 0;
@ -765,18 +765,18 @@ namespace LocalFunctions
#endif #endif
{ {
int t0 = 0; int t0 = 0;
return ZZZ_0(); return ZZZ();
int ZZZ_0() int ZZZ()
{ {
t0 = 0; t0 = 0;
int t2 = t0; int t2 = t0;
return ((Func<int>)delegate { return ((Func<int>)delegate {
t0 = 0; t0 = 0;
t2 = 0; t2 = 0;
return ZZZ_1(); return ZZZ2();
})(); })();
} }
int ZZZ_1() int ZZZ2()
{ {
t0 = 0; t0 = 0;
int t3 = t0; int t3 = t0;
@ -808,18 +808,18 @@ namespace LocalFunctions
#endif #endif
{ {
int t0 = 0; int t0 = 0;
return ZZZ_0() + ZZZ_1(); return ZZZ() + ZZZ2();
int ZZZ_0() int ZZZ()
{ {
t0 = 0; t0 = 0;
int t2 = t0; int t2 = t0;
return ((Func<int>)delegate { return ((Func<int>)delegate {
t0 = 0; t0 = 0;
t2 = 0; t2 = 0;
return ZZZ_1(); return ZZZ2();
})(); })();
} }
int ZZZ_1() int ZZZ2()
{ {
t0 = 0; t0 = 0;
int t3 = t0; int t3 = t0;

24
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -512,14 +512,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// assign names to local functions // assign names to local functions
if (!LocalFunctionDecompiler.ParseLocalFunctionName(function.Name, out _, out var newName) || !IsValidName(newName)) if (!LocalFunctionDecompiler.ParseLocalFunctionName(function.Name, out _, out var newName) || !IsValidName(newName))
newName = null; newName = null;
if (newName == null) string nameWithoutNumber;
int number;
if (!string.IsNullOrEmpty(newName))
{ {
string nameWithoutNumber = "f"; nameWithoutNumber = SplitName(newName, out number);
}
else
{
nameWithoutNumber = "f";
number = 1;
}
int count;
if (!context.IsReservedVariableName(nameWithoutNumber, out int currentIndex)) if (!context.IsReservedVariableName(nameWithoutNumber, out int currentIndex))
{ {
currentIndex = 1; count = 1;
}
else
{
if (currentIndex < number)
count = number;
else
count = Math.Max(number, currentIndex) + 1;
} }
int count = Math.Max(1, currentIndex) + 1;
context.ReserveVariableName(nameWithoutNumber, count); context.ReserveVariableName(nameWithoutNumber, count);
if (count > 1) if (count > 1)
{ {
@ -529,7 +544,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
newName = nameWithoutNumber; newName = nameWithoutNumber;
} }
}
function.Name = newName; function.Name = newName;
function.ReducedMethod.Name = newName; function.ReducedMethod.Name = newName;
context.Add((MethodDefinitionHandle)function.ReducedMethod.MetadataToken, newName); context.Add((MethodDefinitionHandle)function.ReducedMethod.MetadataToken, newName);

6
ILSpy/Properties/Resources.resx

@ -381,6 +381,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.IntroduceLocalFunctions" xml:space="preserve"> <data name="DecompilerSettings.IntroduceLocalFunctions" xml:space="preserve">
<value>Introduce local functions</value> <value>Introduce local functions</value>
</data> </data>
<data name="DecompilerSettings.IntroducePrivateProtectedAccessibility" xml:space="preserve">
<value>Introduce 'private protected' accessibility</value>
</data>
<data name="DecompilerSettings.IntroduceStaticLocalFunctions" xml:space="preserve"> <data name="DecompilerSettings.IntroduceStaticLocalFunctions" xml:space="preserve">
<value>Introduce static local functions</value> <value>Introduce static local functions</value>
</data> </data>
@ -1108,7 +1111,4 @@ Do you want to continue?</value>
<data name="_Window" xml:space="preserve"> <data name="_Window" xml:space="preserve">
<value>_Window</value> <value>_Window</value>
</data> </data>
<data name="DecompilerSettings.IntroducePrivateProtectedAccessibility" xml:space="preserve">
<value>Introduce 'private protected' accessibility</value>
</data>
</root> </root>
Loading…
Cancel
Save