diff --git a/Directory.Build.props b/Directory.Build.props index c6b56b26ad11..ed94e7f27595 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -29,7 +29,7 @@ - latest + preview latest diff --git a/src/linker/Linker.Dataflow/ArrayValue.cs b/src/linker/Linker.Dataflow/ArrayValue.cs index 884e5cd7e0cc..71934bc28ca8 100644 --- a/src/linker/Linker.Dataflow/ArrayValue.cs +++ b/src/linker/Linker.Dataflow/ArrayValue.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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; diff --git a/src/linker/Linker.Dataflow/FieldValue.cs b/src/linker/Linker.Dataflow/FieldValue.cs index 41631512815e..6d20f8301c79 100644 --- a/src/linker/Linker.Dataflow/FieldValue.cs +++ b/src/linker/Linker.Dataflow/FieldValue.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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.Collections.Generic; using System.Diagnostics.CodeAnalysis; diff --git a/src/linker/Linker.Dataflow/GenericParameterValue.cs b/src/linker/Linker.Dataflow/GenericParameterValue.cs index 7f6e104b13c4..f96ae719eac6 100644 --- a/src/linker/Linker.Dataflow/GenericParameterValue.cs +++ b/src/linker/Linker.Dataflow/GenericParameterValue.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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.Collections.Generic; using System.Diagnostics.CodeAnalysis; diff --git a/src/linker/Linker.Dataflow/MethodParameterValue.cs b/src/linker/Linker.Dataflow/MethodParameterValue.cs index 02085722312a..325b02852739 100644 --- a/src/linker/Linker.Dataflow/MethodParameterValue.cs +++ b/src/linker/Linker.Dataflow/MethodParameterValue.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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.Collections.Generic; using System.Diagnostics.CodeAnalysis; diff --git a/src/linker/Linker.Dataflow/MethodReturnValue.cs b/src/linker/Linker.Dataflow/MethodReturnValue.cs index 10414a670940..f6cb423c121e 100644 --- a/src/linker/Linker.Dataflow/MethodReturnValue.cs +++ b/src/linker/Linker.Dataflow/MethodReturnValue.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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.Collections.Generic; using System.Diagnostics.CodeAnalysis; diff --git a/src/linker/Linker.Dataflow/MethodThisParameterValue.cs b/src/linker/Linker.Dataflow/MethodThisParameterValue.cs index e9ded179ba2e..c2f46d5996e1 100644 --- a/src/linker/Linker.Dataflow/MethodThisParameterValue.cs +++ b/src/linker/Linker.Dataflow/MethodThisParameterValue.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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.Collections.Generic; using System.Diagnostics.CodeAnalysis; diff --git a/src/linker/Linker.Dataflow/RuntimeMethodHandleValue.cs b/src/linker/Linker.Dataflow/RuntimeMethodHandleValue.cs index 7197b5491a43..c90ecef4bbb9 100644 --- a/src/linker/Linker.Dataflow/RuntimeMethodHandleValue.cs +++ b/src/linker/Linker.Dataflow/RuntimeMethodHandleValue.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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 ILLink.Shared.DataFlow; using Mono.Cecil; diff --git a/src/linker/Linker.Dataflow/SingleValueExtensions.cs b/src/linker/Linker.Dataflow/SingleValueExtensions.cs index b136c9fef5ca..c0024c1ccc13 100644 --- a/src/linker/Linker.Dataflow/SingleValueExtensions.cs +++ b/src/linker/Linker.Dataflow/SingleValueExtensions.cs @@ -1,5 +1,5 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// 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; diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index cafd61983830..2c9c7e0386f2 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -584,11 +584,15 @@ void ProcessMarkedTypesWithInterfaces () foreach ((var type, var scope) in typesWithInterfaces) { // Exception, types that have not been flagged as instantiated yet. These types may not need their interfaces even if the // interface type is marked - if (!Annotations.IsInstantiated (type) && !Annotations.IsRelevantToVariantCasting (type)) + // UnusedInterfaces optimization is turned off mark all interface implementations + bool unusedInterfacesOptimizationEnabled = Context.IsOptimizationEnabled (CodeOptimizations.UnusedInterfaces, type); + if (!Annotations.IsInstantiated (type) && !Annotations.IsRelevantToVariantCasting (type) && + unusedInterfacesOptimizationEnabled) continue; - using (ScopeStack.PushScope (scope)) + using (ScopeStack.PushScope (scope)) { MarkInterfaceImplementations (type); + } } } @@ -1719,6 +1723,9 @@ void MarkField (FieldDefinition field, in DependencyInfo reason) } } + /// + /// Returns true if the assembly of the is not set to link (i.e. action=copy is set for that assembly) + /// protected virtual bool IgnoreScope (IMetadataScope scope) { AssemblyDefinition? assembly = Context.Resolve (scope); @@ -1915,7 +1922,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in MarkGenericParameterProvider (type); // There are a number of markings we can defer until later when we know it's possible a reference type could be instantiated - // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type + // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type -- Note this is not true for static interfaces // However, for some other types there is no benefit to deferring if (type.IsInterface) { // There's no benefit to deferring processing of an interface type until we know a type implementing that interface is marked @@ -1939,12 +1946,13 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in MarkRequirementsForInstantiatedTypes (type); } + // Save for later once we know which interfaces are marked and then determine which interface implementations and methods to keep if (type.HasInterfaces) _typesWithInterfaces.Add ((type, ScopeStack.CurrentScope)); if (type.HasMethods) { - // For virtuals that must be preserved, blame the declaring type. - MarkMethodsIf (type.Methods, IsVirtualNeededByTypeDueToPreservedScope, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type)); + // For methods that must be preserved, blame the declaring type. + MarkMethodsIf (type.Methods, IsMethodNeededByTypeDueToPreservedScope, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type)); if (ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { using (ScopeStack.PopToParent ()) MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type)); @@ -2278,9 +2286,19 @@ void MarkGenericParameter (GenericParameter parameter) } } - bool IsVirtualNeededByTypeDueToPreservedScope (MethodDefinition method) - { - if (!method.IsVirtual) + /// + /// Returns true if any of the base methods of the passed is in an assembly that is not trimmed (i.e. action != trim). + /// Meant to be used to determine whether methods should be marked regardless of whether it is instantiated or not. + /// + /// + /// When the unusedinterfaces optimization is on, this is used to mark methods that override an abstract method from a non-link assembly and must be kept. + /// When the unusedinterfaces optimization is off, this will do the same as when on but will also mark interface methods from interfaces defined in a non-link assembly. + /// If the containing type is instantiated, the caller should also use + /// + bool IsMethodNeededByTypeDueToPreservedScope (MethodDefinition method) + { + // Static methods may also have base methods in static interface methods. These methods are not captured by IsVirtual and must be checked separately + if (!(method.IsVirtual || method.IsStatic)) return false; var base_list = Annotations.GetBaseMethods (method); @@ -2289,8 +2307,8 @@ bool IsVirtualNeededByTypeDueToPreservedScope (MethodDefinition method) foreach (MethodDefinition @base in base_list) { // Just because the type is marked does not mean we need interface methods. - // if the type is never instantiated, interfaces will be removed - if (@base.DeclaringType.IsInterface) + // if the type is never instantiated, interfaces will be removed - but only if the optimization is enabled + if (@base.DeclaringType.IsInterface && Context.IsOptimizationEnabled (CodeOptimizations.UnusedInterfaces, method.DeclaringType)) continue; // If the type is marked, we need to keep overrides of abstract members defined in assemblies @@ -2302,15 +2320,24 @@ bool IsVirtualNeededByTypeDueToPreservedScope (MethodDefinition method) if (IgnoreScope (@base.DeclaringType.Scope)) return true; - if (IsVirtualNeededByTypeDueToPreservedScope (@base)) + if (IsMethodNeededByTypeDueToPreservedScope (@base)) return true; } return false; } - bool IsVirtualNeededByInstantiatedTypeDueToPreservedScope (MethodDefinition method) + /// + /// Returns true if any of the base methods of is defined in an assembly that is not trimmed (i.e. action!=trim). + /// This is meant to be used on methods from a type that is known to be instantiated. + /// + /// + /// This is very similar to , + /// but will mark methods from an interface defined in a non-link assembly regardless of the optimization, and does not handle static interface methods. + /// + bool IsMethodNeededByInstantiatedTypeDueToPreservedScope (MethodDefinition method) { + // Any static interface methods are captured by , which should be called on all relevant methods so no need to check again here. if (!method.IsVirtual) return false; @@ -2322,7 +2349,7 @@ bool IsVirtualNeededByInstantiatedTypeDueToPreservedScope (MethodDefinition meth if (IgnoreScope (@base.DeclaringType.Scope)) return true; - if (IsVirtualNeededByTypeDueToPreservedScope (@base)) + if (IsMethodNeededByTypeDueToPreservedScope (@base)) return true; } @@ -3110,7 +3137,7 @@ protected virtual void MarkRequirementsForInstantiatedTypes (TypeDefinition type protected virtual IEnumerable GetRequiredMethodsForInstantiatedType (TypeDefinition type) { foreach (var method in type.Methods) { - if (IsVirtualNeededByInstantiatedTypeDueToPreservedScope (method)) + if (IsMethodNeededByInstantiatedTypeDueToPreservedScope (method)) yield return method; } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs index 7b604a38ad55..74ea1c72d468 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs @@ -21,5 +21,11 @@ public Task InterfaceOnUninstantiatedTypeRemoved () return RunTest (allowMissingWarnings: true); } + [Fact] + public Task InterfaceVariants () + { + return RunTest (allowMissingWarnings: true); + } + } } \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/CopyLibrary.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/CopyLibrary.cs new file mode 100644 index 000000000000..655198709b1c --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/CopyLibrary.cs @@ -0,0 +1,17 @@ +// 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. + +namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.Dependencies +{ + public interface ICopyLibraryInterface + { + void CopyLibraryInterfaceMethod (); + void CopyLibraryExplicitImplementationInterfaceMethod (); + } + + public interface ICopyLibraryStaticInterface + { + static abstract void CopyLibraryStaticInterfaceMethod (); + static abstract void CopyLibraryExplicitImplementationStaticInterfaceMethod (); + } +} diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceOnUninstantiatedTypeRemoved.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceOnUninstantiatedTypeRemoved.cs index 6b2cbd51104c..1c4a08112c3e 100644 --- a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceOnUninstantiatedTypeRemoved.cs +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceOnUninstantiatedTypeRemoved.cs @@ -3,7 +3,6 @@ namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces { - [SetupLinkerArgument ("--disable-opt", "unusedinterfaces")] public class InterfaceOnUninstantiatedTypeRemoved { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceVariants.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceVariants.cs new file mode 100644 index 000000000000..f9d54d009cf1 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceVariants.cs @@ -0,0 +1,242 @@ +// 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; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.Inheritance.Interfaces.Dependencies; + +namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces +{ + [SetupCompileBefore ("copylibrary.dll", new[] { "Dependencies/CopyLibrary.cs" })] + [SetupLinkerAction ("copy", "copylibrary")] + public class InterfaceVariants + { + public static void Main () + { + Type t = typeof (UninstantiatedPublicClassWithInterface); + t = typeof (UninstantiatedPublicClassWithImplicitlyImplementedInterface); + t = typeof (UninstantiatedPublicClassWithPrivateInterface); + + UninstantiatedPublicClassWithInterface.InternalStaticInterfaceMethodUsed (); + InstantiatedClassWithInterfaces.InternalStaticInterfaceMethodUsed (); + + // Use all public interfaces - they're marked as public only to denote them as "used" + typeof (IPublicInterface).RequiresPublicMethods (); + typeof (IPublicStaticInterface).RequiresPublicMethods (); + + var a = new InstantiatedClassWithInterfaces (); + } + + [Kept] + [KeptInterface (typeof (IEnumerator))] + [KeptInterface (typeof (IPublicInterface))] + [KeptInterface (typeof (IPublicStaticInterface))] + [KeptInterface (typeof (IInternalStaticInterfaceWithUsedMethod))] // https://github.com/dotnet/linker/issues/2733 + [KeptInterface (typeof (ICopyLibraryInterface))] + [KeptInterface (typeof (ICopyLibraryStaticInterface))] + public class UninstantiatedPublicClassWithInterface : + IPublicInterface, + IPublicStaticInterface, + IInternalInterface, + IInternalStaticInterface, + IInternalStaticInterfaceWithUsedMethod, + IEnumerator, + ICopyLibraryInterface, + ICopyLibraryStaticInterface + { + internal UninstantiatedPublicClassWithInterface () { } + + [Kept] + public void PublicInterfaceMethod () { } + + [Kept] + void IPublicInterface.ExplicitImplementationPublicInterfaceMethod () { } + + [Kept] + public static void PublicStaticInterfaceMethod () { } + + [Kept] + static void IPublicStaticInterface.ExplicitImplementationPublicStaticInterfaceMethod () { } + + public void InternalInterfaceMethod () { } + + void IInternalInterface.ExplicitImplementationInternalInterfaceMethod () { } + + public static void InternalStaticInterfaceMethod () { } + + static void IInternalStaticInterface.ExplicitImplementationInternalStaticInterfaceMethod () { } + + [Kept] + public static void InternalStaticInterfaceMethodUsed () { } + + [Kept] + [ExpectBodyModified] + bool IEnumerator.MoveNext () { throw new PlatformNotSupportedException (); } + + [Kept] + object IEnumerator.Current { + [Kept] + [ExpectBodyModified] + get { throw new PlatformNotSupportedException (); } + } + + [Kept] + void IEnumerator.Reset () { } + + [Kept] + public void CopyLibraryInterfaceMethod () { } + + [Kept] + void ICopyLibraryInterface.CopyLibraryExplicitImplementationInterfaceMethod () { } + + [Kept] + public static void CopyLibraryStaticInterfaceMethod () { } + + [Kept] + static void ICopyLibraryStaticInterface.CopyLibraryExplicitImplementationStaticInterfaceMethod () { } + } + + [Kept] + [KeptInterface (typeof (IFormattable))] + public class UninstantiatedPublicClassWithImplicitlyImplementedInterface : IInternalInterface, IFormattable + { + internal UninstantiatedPublicClassWithImplicitlyImplementedInterface () { } + + public void InternalInterfaceMethod () { } + + void IInternalInterface.ExplicitImplementationInternalInterfaceMethod () { } + + [Kept] + [ExpectBodyModified] + [ExpectLocalsModified] + public string ToString (string format, IFormatProvider formatProvider) + { + return "formatted string"; + } + } + + [Kept] + [KeptInterface (typeof (IEnumerator))] + [KeptInterface (typeof (IPublicInterface))] + [KeptInterface (typeof (IPublicStaticInterface))] + [KeptInterface (typeof (IInternalStaticInterfaceWithUsedMethod))] // https://github.com/dotnet/linker/issues/2733 + [KeptInterface (typeof (ICopyLibraryInterface))] + [KeptInterface (typeof (ICopyLibraryStaticInterface))] + public class InstantiatedClassWithInterfaces : + IPublicInterface, + IPublicStaticInterface, + IInternalInterface, + IInternalStaticInterface, + IInternalStaticInterfaceWithUsedMethod, + IEnumerator, + ICopyLibraryInterface, + ICopyLibraryStaticInterface + { + [Kept] + public InstantiatedClassWithInterfaces () { } + + [Kept] + public void PublicInterfaceMethod () { } + + [Kept] + void IPublicInterface.ExplicitImplementationPublicInterfaceMethod () { } + + [Kept] + public static void PublicStaticInterfaceMethod () { } + + [Kept] + static void IPublicStaticInterface.ExplicitImplementationPublicStaticInterfaceMethod () { } + + public void InternalInterfaceMethod () { } + + void IInternalInterface.ExplicitImplementationInternalInterfaceMethod () { } + + public static void InternalStaticInterfaceMethod () { } + + static void IInternalStaticInterface.ExplicitImplementationInternalStaticInterfaceMethod () { } + + [Kept] + public static void InternalStaticInterfaceMethodUsed () { } + + [Kept] + bool IEnumerator.MoveNext () { throw new PlatformNotSupportedException (); } + + [Kept] + object IEnumerator.Current { [Kept] get { throw new PlatformNotSupportedException (); } } + + [Kept] + void IEnumerator.Reset () { } + + [Kept] + public void CopyLibraryInterfaceMethod () { } + + [Kept] + void ICopyLibraryInterface.CopyLibraryExplicitImplementationInterfaceMethod () { } + + [Kept] + public static void CopyLibraryStaticInterfaceMethod () { } + + [Kept] + static void ICopyLibraryStaticInterface.CopyLibraryExplicitImplementationStaticInterfaceMethod () { } + } + + [Kept] + public class UninstantiatedPublicClassWithPrivateInterface : IPrivateInterface + { + internal UninstantiatedPublicClassWithPrivateInterface () { } + + void IPrivateInterface.PrivateInterfaceMethod () { } + } + + [Kept] + public interface IPublicInterface + { + [Kept] + void PublicInterfaceMethod (); + + [Kept] + void ExplicitImplementationPublicInterfaceMethod (); + } + + [Kept] + public interface IPublicStaticInterface + { + [Kept] + static abstract void PublicStaticInterfaceMethod (); + + [Kept] + static abstract void ExplicitImplementationPublicStaticInterfaceMethod (); + } + + internal interface IInternalInterface + { + void InternalInterfaceMethod (); + + void ExplicitImplementationInternalInterfaceMethod (); + } + + internal interface IInternalStaticInterface + { + static abstract void InternalStaticInterfaceMethod (); + + static abstract void ExplicitImplementationInternalStaticInterfaceMethod (); + } + + // The interface methods themselves are not used, but the implentation of these methods is + // https://github.com/dotnet/linker/issues/2733 + [Kept] + internal interface IInternalStaticInterfaceWithUsedMethod + { + [Kept] // https://github.com/dotnet/linker/issues/2733 + static abstract void InternalStaticInterfaceMethodUsed (); + } + + private interface IPrivateInterface + { + void PrivateInterfaceMethod (); + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/Libraries/Dependencies/CopyLibrary.cs b/test/Mono.Linker.Tests.Cases/Libraries/Dependencies/CopyLibrary.cs new file mode 100644 index 000000000000..0f31e8277c37 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Libraries/Dependencies/CopyLibrary.cs @@ -0,0 +1,17 @@ +// 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. + +namespace Mono.Linker.Tests.Cases.Libraries.Dependencies +{ + public interface ICopyLibraryInterface + { + void CopyLibraryInterfaceMethod (); + void CopyLibraryExplicitImplementationInterfaceMethod (); + } + + public interface ICopyLibraryStaticInterface + { + static abstract void CopyLibraryStaticInterfaceMethod (); + static abstract void CopyLibraryExplicitImplementationStaticInterfaceMethod (); + } +} diff --git a/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs b/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs index e9e7ecf29ee6..82f78a8c80bf 100644 --- a/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs +++ b/test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs @@ -1,11 +1,18 @@ +// 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; using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Runtime.Serialization; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.Libraries.Dependencies; namespace Mono.Linker.Tests.Cases.Libraries { + [SetupCompileBefore ("copylibrary.dll", new[] { "Dependencies/CopyLibrary.cs" })] + [SetupLinkerAction ("copy", "copylibrary")] [SetupLinkerArgument ("-a", "test.exe", "library")] [SetupLinkerArgument ("--enable-opt", "ipconstprop")] [VerifyMetadataNames] @@ -173,6 +180,204 @@ public override string ToString () public interface I { } + + [Kept] + [KeptInterface (typeof (IEnumerator))] + [KeptInterface (typeof (IPublicInterface))] + [KeptInterface (typeof (IPublicStaticInterface))] + [KeptInterface (typeof (IInternalInterface))] + [KeptInterface (typeof (IInternalStaticInterface))] + [KeptInterface (typeof (ICopyLibraryInterface))] + [KeptInterface (typeof (ICopyLibraryStaticInterface))] + public class UninstantiatedPublicClassWithInterface : + IPublicInterface, + IPublicStaticInterface, + IInternalInterface, + IInternalStaticInterface, + IEnumerator, + ICopyLibraryInterface, + ICopyLibraryStaticInterface + { + internal UninstantiatedPublicClassWithInterface () { } + + [Kept] + public void PublicInterfaceMethod () { } + + [Kept] + void IPublicInterface.ExplicitImplementationPublicInterfaceMethod () { } + + [Kept] + public static void PublicStaticInterfaceMethod () { } + + [Kept] + static void IPublicStaticInterface.ExplicitImplementationPublicStaticInterfaceMethod () { } + + [Kept] + public void InternalInterfaceMethod () { } + + void IInternalInterface.ExplicitImplementationInternalInterfaceMethod () { } + + [Kept] + public static void InternalStaticInterfaceMethod () { } + + static void IInternalStaticInterface.ExplicitImplementationInternalStaticInterfaceMethod () { } + + [Kept] + bool IEnumerator.MoveNext () { throw new PlatformNotSupportedException (); } + + [Kept] + object IEnumerator.Current { [Kept] get { throw new PlatformNotSupportedException (); } } + + [Kept] + void IEnumerator.Reset () { } + + [Kept] + public void CopyLibraryInterfaceMethod () { } + + [Kept] + void ICopyLibraryInterface.CopyLibraryExplicitImplementationInterfaceMethod () { } + + [Kept] + public static void CopyLibraryStaticInterfaceMethod () { } + + [Kept] + static void ICopyLibraryStaticInterface.CopyLibraryExplicitImplementationStaticInterfaceMethod () { } + } + + [Kept] + [KeptInterface (typeof (IInternalInterface))] + [KeptInterface (typeof (IFormattable))] + public class UninstantiatedPublicClassWithImplicitlyImplementedInterface : IInternalInterface, IFormattable + { + internal UninstantiatedPublicClassWithImplicitlyImplementedInterface () { } + + [Kept] + public void InternalInterfaceMethod () { } + + void IInternalInterface.ExplicitImplementationInternalInterfaceMethod () { } + + [Kept] + public string ToString (string format, IFormatProvider formatProvider) + { + return "formatted string"; + } + } + + [Kept] + [KeptInterface (typeof (IEnumerator))] + [KeptInterface (typeof (IPublicInterface))] + [KeptInterface (typeof (IPublicStaticInterface))] + [KeptInterface (typeof (IInternalInterface))] + [KeptInterface (typeof (IInternalStaticInterface))] + [KeptInterface (typeof (ICopyLibraryInterface))] + [KeptInterface (typeof (ICopyLibraryStaticInterface))] + public class InstantiatedClassWithInterfaces : + IPublicInterface, + IPublicStaticInterface, + IInternalInterface, + IInternalStaticInterface, + IEnumerator, + ICopyLibraryInterface, + ICopyLibraryStaticInterface + { + [Kept] + public InstantiatedClassWithInterfaces () { } + + [Kept] + public void PublicInterfaceMethod () { } + + [Kept] + void IPublicInterface.ExplicitImplementationPublicInterfaceMethod () { } + + [Kept] + public static void PublicStaticInterfaceMethod () { } + + [Kept] + static void IPublicStaticInterface.ExplicitImplementationPublicStaticInterfaceMethod () { } + + [Kept] + public void InternalInterfaceMethod () { } + + void IInternalInterface.ExplicitImplementationInternalInterfaceMethod () { } + + [Kept] + public static void InternalStaticInterfaceMethod () { } + + static void IInternalStaticInterface.ExplicitImplementationInternalStaticInterfaceMethod () { } + + [Kept] + bool IEnumerator.MoveNext () { throw new PlatformNotSupportedException (); } + + [Kept] + object IEnumerator.Current { [Kept] get { throw new PlatformNotSupportedException (); } } + + [Kept] + void IEnumerator.Reset () { } + + [Kept] + public void CopyLibraryInterfaceMethod () { } + + [Kept] + void ICopyLibraryInterface.CopyLibraryExplicitImplementationInterfaceMethod () { } + + [Kept] + public static void CopyLibraryStaticInterfaceMethod () { } + + [Kept] + static void ICopyLibraryStaticInterface.CopyLibraryExplicitImplementationStaticInterfaceMethod () { } + } + + [Kept] + [KeptInterface (typeof (IPrivateInterface))] + public class UninstantiatedPublicClassWithPrivateInterface : IPrivateInterface + { + internal UninstantiatedPublicClassWithPrivateInterface () { } + + void IPrivateInterface.PrivateInterfaceMethod () { } + } + + [Kept] + public interface IPublicInterface + { + [Kept] + void PublicInterfaceMethod (); + + [Kept] + void ExplicitImplementationPublicInterfaceMethod (); + } + + [Kept] + public interface IPublicStaticInterface + { + [Kept] + static abstract void PublicStaticInterfaceMethod (); + + [Kept] + static abstract void ExplicitImplementationPublicStaticInterfaceMethod (); + } + + [Kept] + internal interface IInternalInterface + { + void InternalInterfaceMethod (); + + void ExplicitImplementationInternalInterfaceMethod (); + } + + [Kept] + internal interface IInternalStaticInterface + { + [Kept] // https://github.com/dotnet/linker/issues/2733 + static abstract void InternalStaticInterfaceMethod (); + + static abstract void ExplicitImplementationInternalStaticInterfaceMethod (); + } + + [Kept] + private interface IPrivateInterface + { + void PrivateInterfaceMethod (); + } } internal class RootLibrary_Internal diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs index 8aeb92da83ed..991c1860e4a8 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs @@ -234,7 +234,7 @@ protected virtual NPath CompileCSharpAssemblyWithDefaultCompiler (CompilerOption #if NETCOREAPP protected virtual NPath CompileCSharpAssemblyWithRoslyn (CompilerOptions options) { - var languageVersion = LanguageVersion.Default; + var languageVersion = LanguageVersion.Preview; var compilationOptions = new CSharpCompilationOptions ( outputKind: options.OutputPath.FileName.EndsWith (".exe") ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary, assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default