// Remove ",nq" suffix if present
// (it asks the expression evaluator to remove the quotes when displaying the final value)
- if (ContainsNqSuffixRegex ().IsMatch(realMatch)) {
+ if (ContainsNqSuffixRegex ().IsMatch (realMatch)) {
realMatch = realMatch.Substring (0, realMatch.LastIndexOf (','));
}
}
if (method.HasOverrides) {
+ var assembly = Context.Resolve (method.DeclaringType.Scope);
+ // If this method is in a Copy or CopyUsed assembly, .overrides won't get swept and we need to keep all of them
+ bool markAllOverrides = assembly != null && Annotations.GetAction (assembly) is AssemblyAction.Copy or AssemblyAction.CopyUsed;
foreach (MethodReference @base in method.Overrides) {
// Method implementing a static interface method will have an override to it - note instance methods usually don't unless they're explicit.
// Calling the implementation method directly has no impact on the interface, and as such it should not mark the interface or its method.
// Only if the interface method is referenced, then all the methods which implemented must be kept, but not the other way round.
- if (Context.Resolve (@base) is MethodDefinition baseDefinition
+ if (!markAllOverrides &&
+ Context.Resolve (@base) is MethodDefinition baseDefinition
&& new OverrideInformation.OverridePair (baseDefinition, method).IsStaticInterfaceMethodPair ())
continue;
MarkMethod (@base, new DependencyInfo (DependencyKind.MethodImplOverride, method), ScopeStack.CurrentScope.Origin);
--- /dev/null
+// 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;
+using Mono.Linker.Tests.Cases.Inheritance.Interfaces.StaticInterfaceMethods.Dependencies;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.StaticInterfaceMethods
+{
+ [KeptMemberInAssembly ("library", typeof (IStaticAbstractMethods), "Method()", "get_Property()", "Property", "set_Property(System.Int32)")]
+ [SetupCompileBefore ("library.dll", new[] { "Dependencies/Library.cs" })]
+ [SetupLinkerAction ("link", "library")]
+ [SetupLinkerAction ("copy", "test")]
+ /// <summary>
+ /// Regression test for issue: https://github.com/dotnet/runtime/issues/81746
+ /// OverridesStaticInterfaceMethods.Method() (and Property.set/get) has an entry in .overrides pointing to ISataticAbstractMethods.Method.
+ /// IStaticAbstractMethods.Method() isn't referenced anywhere else and isn't otherwise needed.
+ /// Usually the interface method could be removed, and the pointer to it in the .overrides metadata would be removed
+ /// However, since OverridesStaticInterfaceMethods is in a 'copy' assembly, the .overrides metadata isn't swept. If we remove the method from the interface,
+ /// we have a "dangling reference" which makes the metadata invalid.
+ /// </summary>
+ static class OverrideInCopyAssembly
+ {
+ [Kept]
+ public static void Main ()
+ {
+ OverridesStaticInterfaceMethods.Property = OverridesStaticInterfaceMethods.Method ();
+ var x = OverridesStaticInterfaceMethods.Property;
+ }
+ [Kept]
+ [KeptMember (".ctor()")]
+ [KeptInterface (typeof (IStaticAbstractMethods))]
+ class OverridesStaticInterfaceMethods : IStaticAbstractMethods
+ {
+ [Kept]
+ public static int Property {
+ [Kept]
+ [KeptOverride (typeof (IStaticAbstractMethods))]
+ get => throw new NotImplementedException ();
+ [Kept]
+ [KeptOverride (typeof (IStaticAbstractMethods))]
+ set => throw new NotImplementedException ();
+ }
+ [Kept]
+ [KeptOverride (typeof (IStaticAbstractMethods))]
+
+ public static int Method () => throw new NotImplementedException ();
+ [Kept]
+ public int InstanceMethod () => throw new NotImplementedException ();
+ }
+ }
+}