From 7e08c348b5665256c7d1379cc94ff62cc2eaf606 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 11 May 2022 23:16:01 +0200 Subject: [PATCH] #2685: Emit 'override' without 'newslot' as 'virtual' if there is no (known) method to override. --- .../TestCases/ILPretty/FSharpLoops_Debug.cs | 4 +-- .../TestCases/ILPretty/FSharpLoops_Release.cs | 4 +-- .../TestCases/ILPretty/SequenceOfNestedIfs.cs | 4 +-- .../TestCases/ILPretty/UnknownTypes.cs | 2 +- .../CSharp/CSharpDecompiler.cs | 33 ++++++++++++++----- ICSharpCode.Decompiler/DecompileRun.cs | 2 ++ 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs index c2a148c2a..584b75b18 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs @@ -92,7 +92,7 @@ public static class Program pc = 2; } - public override bool get_CheckClose() + public bool get_CheckClose() { switch (pc) { @@ -106,7 +106,7 @@ public static class Program [DebuggerNonUserCode] [CompilerGenerated] - public override int get_LastGenerated() + public int get_LastGenerated() { return current; } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs index eb885b071..7d6c0e14b 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs @@ -93,7 +93,7 @@ public static class Program pc = 2; } - public override bool get_CheckClose() + public bool get_CheckClose() { switch (pc) { @@ -107,7 +107,7 @@ public static class Program [DebuggerNonUserCode] [CompilerGenerated] - public override int get_LastGenerated() + public int get_LastGenerated() { return current; } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/SequenceOfNestedIfs.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/SequenceOfNestedIfs.cs index 3f14f4638..9603be34d 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/SequenceOfNestedIfs.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/SequenceOfNestedIfs.cs @@ -12,11 +12,11 @@ public class SequenceOfNestedIfs { public bool _clear; public Material _material; - public override bool CheckShader() + public virtual bool CheckShader() { return false; } - public override void CreateMaterials() + public virtual void CreateMaterials() { if (!_clear) { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/UnknownTypes.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/UnknownTypes.cs index c77ae5e14..b834dae1b 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/UnknownTypes.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/UnknownTypes.cs @@ -2,7 +2,7 @@ internal class UnknownTypes { private readonly IInterface memberField; - public override bool CanExecute(CallbackQuery message) + public virtual bool CanExecute(CallbackQuery message) { return ((IInterface)(object)memberField).Execute(new SomeClass { ChatId = StaticClass.GetChatId(message), diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 3af5d305d..52078eb82 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -1570,14 +1570,16 @@ namespace ICSharpCode.Decompiler.CSharp { SetNewModifier(methodDecl); } - //else if (!method.IsVirtual && method.IsOverride && InheritanceHelper.GetBaseMember(method) == null) - //{ - // methodDecl.Modifiers &= ~Modifiers.Override; - // if (!method.DeclaringTypeDefinition.IsSealed) - // { - // methodDecl.Modifiers |= Modifiers.Virtual; - // } - //} + else if (!method.IsStatic && !method.IsExplicitInterfaceImplementation + && !method.IsVirtual && method.IsOverride + && InheritanceHelper.GetBaseMember(method) == null && IsTypeHierarchyKnown(method.DeclaringType)) + { + methodDecl.Modifiers &= ~Modifiers.Override; + if (!method.DeclaringTypeDefinition.IsSealed) + { + methodDecl.Modifiers |= Modifiers.Virtual; + } + } if (IsCovariantReturnOverride(method)) { RemoveAttribute(methodDecl, KnownAttribute.PreserveBaseOverrides); @@ -1585,6 +1587,21 @@ namespace ICSharpCode.Decompiler.CSharp methodDecl.Modifiers |= Modifiers.Override; } return methodDecl; + + bool IsTypeHierarchyKnown(IType type) + { + var definition = type.GetDefinition(); + if (definition == null) + { + return false; + } + + if (decompileRun.TypeHierarchyIsKnown.TryGetValue(definition, out var value)) + return value; + value = method.DeclaringType.GetNonInterfaceBaseTypes().All(t => t.Kind != TypeKind.Unknown); + decompileRun.TypeHierarchyIsKnown.Add(definition, value); + return value; + } } finally { diff --git a/ICSharpCode.Decompiler/DecompileRun.cs b/ICSharpCode.Decompiler/DecompileRun.cs index 4d278ab7f..2692ddf1a 100644 --- a/ICSharpCode.Decompiler/DecompileRun.cs +++ b/ICSharpCode.Decompiler/DecompileRun.cs @@ -19,6 +19,8 @@ namespace ICSharpCode.Decompiler public IDocumentationProvider DocumentationProvider { get; set; } public Dictionary RecordDecompilers { get; } = new Dictionary(); + public Dictionary TypeHierarchyIsKnown { get; } = new(); + Lazy usingScope => new Lazy(() => CreateUsingScope(Namespaces));