Skip to content

Commit

Permalink
Don't mark override of abstract base if the override's declaring type…
Browse files Browse the repository at this point in the history
… is not marked (dotnet/linker#3098)

* Don't mark an override every time the base is abstract, only if the declaring type is also marked
Adds a condition to ShouldMarkOverrideForBase to exit early if the declaring type of the method is not marked.

Commit migrated from dotnet/linker@391ac60
  • Loading branch information
jtschuster authored Nov 2, 2022
1 parent 7b603fa commit 8c5cfa6
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/tools/illink/src/linker/Linker.Steps/MarkStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public Task NeverInstantiatedTypeWithBaseInCopiedAssembly ()
return RunTest (allowMissingWarnings: true);
}

[Fact]
public Task OverrideInUnmarkedClassIsRemoved ()
{
return RunTest (allowMissingWarnings: true);
}

[Fact]
public Task UnusedTypeWithOverrideOfVirtualMethodIsRemoved ()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
}

0 comments on commit 8c5cfa6

Please sign in to comment.