diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index e8c29e29e075..7f26bea95161 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -723,6 +723,8 @@ void ProcessVirtualMethod (MethodDefinition method) // TODO: Move interface method marking logic here https://github.com/dotnet/linker/issues/3090 bool ShouldMarkOverrideForBase (OverrideInformation overrideInformation) { + if (!Annotations.IsMarked (overrideInformation.Override.DeclaringType)) + return false; if (overrideInformation.IsOverrideOfInterfaceMember) { _interfaceOverrides.Add ((overrideInformation, ScopeStack.CurrentScope)); return false; diff --git a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.VirtualMethodsTests.g.cs b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.VirtualMethodsTests.g.cs index a7cadcdb33e0..5ddfcf4f3b67 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.VirtualMethodsTests.g.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.VirtualMethodsTests.g.cs @@ -27,6 +27,12 @@ public Task NeverInstantiatedTypeWithBaseInCopiedAssembly () return RunTest (allowMissingWarnings: true); } + [Fact] + public Task OverrideInUnmarkedClassIsRemoved () + { + return RunTest (allowMissingWarnings: true); + } + [Fact] public Task UnusedTypeWithOverrideOfVirtualMethodIsRemoved () { diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.VirtualMethods/OverrideOfAbstractInUnmarkedClassIsRemoved.cs b/test/Mono.Linker.Tests.Cases/Inheritance.VirtualMethods/OverrideOfAbstractInUnmarkedClassIsRemoved.cs new file mode 100644 index 000000000000..366fd6a3f34f --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Inheritance.VirtualMethods/OverrideOfAbstractInUnmarkedClassIsRemoved.cs @@ -0,0 +1,97 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Inheritance.VirtualMethods +{ + public class OverrideOfAbstractInUnmarkedClassIsRemoved + { + [Kept] + public static void Main () + { + MarkedBase x = new MarkedDerived (); + x.Method (); + + UsedSecondLevelTypeWithAbstractBase y = new (); + y.Method (); + + UsedSecondLevelType z = new (); + z.Method (); + } + + [Kept] + [KeptMember (".ctor()")] + abstract class MarkedBase + { + [Kept] + public abstract int Method (); + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (MarkedBase))] + class MarkedDerived : MarkedBase + { + [Kept] + public override int Method () => 1; + } + + class UnmarkedDerived : MarkedBase + { + public override int Method () => 1; + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (MarkedBase))] + class UnusedIntermediateType : MarkedBase + { + [Kept] + public override int Method () => 1; + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (UnusedIntermediateType))] + class UsedSecondLevelType : UnusedIntermediateType + { + [Kept] + public override int Method () => 1; + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (MarkedBase))] + abstract class UnusedIntermediateTypeWithAbstractOverride : MarkedBase + { + [Kept] + public abstract override int Method (); + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (UnusedIntermediateTypeWithAbstractOverride))] + class UsedSecondLevelTypeWithAbstractBase : UnusedIntermediateTypeWithAbstractOverride + { + [Kept] + public override int Method () => 1; + } + + class UnusedSecondLevelTypeWithAbstractBase : UnusedIntermediateTypeWithAbstractOverride + { + public override int Method () => 1; + } + + class UnusedSecondLevelType : UnusedIntermediateType + { + public override int Method () => 1; + } + } +}