Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJackson Schuster <36744439+jtschuster@users.noreply.github.com>2022-04-12 23:34:39 +0300
committerGitHub <noreply@github.com>2022-04-12 23:34:39 +0300
commit8c33ad3ad8cba002301cf7341ba9003379247edb (patch)
tree36a5fd293855a21df9a1f3ec3332c6a2c12a0b6c
parent805c6a7f868348bc2400fcacb4f00998bd67b60d (diff)
Don't remove unused interfaces in library mode (#2711)
This will make sure that we keep all interfaces and all interface method implementations on such type. * Change the solution to rely on the optimization setting only * wip * Add implicit interface implementation case * Edit tests to remove issue-specific code and names * Mark members of CollectedType as kept * Add private interface test and simplify external interface example * Replace early exit for non-interfaces * License headers and use IsMethodNeededByTypeDueToPreservedScope instead of Interface specific version * Add check for static methods before skipping virtual marking Check for optimization before skipping marking interface methods for PreservedScope Add doc comments * Add more clarifying comments, move static method check, rename method Rename IsVirtualNeededByInstantiatedTypeDueToPreservedScope to IsOverrideNeededByInstantiatedTypeDueToPreservedScope Added more comments describing purpose of methods Moved the static interface method check to the method that is called on all types regardless of instantiation * Renames and comment cleanup + tests This doesn't change product behavior, only renamed methods and improved comments. Added new tests for the RootLibrary: - Added a dependency to an "copy" assembly (mainly because I can define a static interface in it) - Added more combinations to the interfaces/classes in the test - Since this uses static interface methods I had to enable "preview" language features for the test project and for the test infra. * More tests for interface behavior Co-authored-by: vitek-karas <vitek.karas@microsoft.com> Co-authored-by: vitek-karas <10670590+vitek-karas@users.noreply.github.com>
-rw-r--r--Directory.Build.props2
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs55
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs6
-rw-r--r--test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/CopyLibrary.cs17
-rw-r--r--test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceOnUninstantiatedTypeRemoved.cs1
-rw-r--r--test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceVariants.cs242
-rw-r--r--test/Mono.Linker.Tests.Cases/Libraries/Dependencies/CopyLibrary.cs17
-rw-r--r--test/Mono.Linker.Tests.Cases/Libraries/RootLibrary.cs207
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs2
9 files changed, 531 insertions, 18 deletions
diff --git a/Directory.Build.props b/Directory.Build.props
index c6b56b26a..ed94e7f27 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -29,7 +29,7 @@
</PropertyGroup>
<PropertyGroup>
- <LangVersion>latest</LangVersion>
+ <LangVersion>preview</LangVersion>
<AnalysisLevel>latest</AnalysisLevel>
</PropertyGroup>
</Project>
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index cafd61983..2c9c7e038 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -584,11 +584,15 @@ namespace Mono.Linker.Steps
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 @@ namespace Mono.Linker.Steps
}
}
+ /// <summary>
+ /// Returns true if the assembly of the <paramref name="scope"></paramref> is not set to link (i.e. action=copy is set for that assembly)
+ /// </summary>
protected virtual bool IgnoreScope (IMetadataScope scope)
{
AssemblyDefinition? assembly = Context.Resolve (scope);
@@ -1915,7 +1922,7 @@ namespace Mono.Linker.Steps
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 @@ namespace Mono.Linker.Steps
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 @@ namespace Mono.Linker.Steps
}
}
- bool IsVirtualNeededByTypeDueToPreservedScope (MethodDefinition method)
- {
- if (!method.IsVirtual)
+ /// <summary>
+ /// Returns true if any of the base methods of the <paramref name="method"/> 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.
+ /// </summary>
+ /// <remarks>
+ /// 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 <see cref="IsMethodNeededByInstantiatedTypeDueToPreservedScope (MethodDefinition)" />
+ /// </remarks>
+ 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 @@ namespace Mono.Linker.Steps
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 @@ namespace Mono.Linker.Steps
if (IgnoreScope (@base.DeclaringType.Scope))
return true;
- if (IsVirtualNeededByTypeDueToPreservedScope (@base))
+ if (IsMethodNeededByTypeDueToPreservedScope (@base))
return true;
}
return false;
}
- bool IsVirtualNeededByInstantiatedTypeDueToPreservedScope (MethodDefinition method)
+ /// <summary>
+ /// Returns true if any of the base methods of <paramref name="method" /> 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.
+ /// </summary>
+ /// <remarks>
+ /// This is very similar to <see cref="IsMethodNeededByTypeDueToPreservedScope (MethodDefinition)"/>,
+ /// but will mark methods from an interface defined in a non-link assembly regardless of the optimization, and does not handle static interface methods.
+ /// </remarks>
+ bool IsMethodNeededByInstantiatedTypeDueToPreservedScope (MethodDefinition method)
{
+ // Any static interface methods are captured by <see cref="IsVirtualNeededByTypeDueToPreservedScope">, which should be called on all relevant methods so no need to check again here.
if (!method.IsVirtual)
return false;
@@ -2322,7 +2349,7 @@ namespace Mono.Linker.Steps
if (IgnoreScope (@base.DeclaringType.Scope))
return true;
- if (IsVirtualNeededByTypeDueToPreservedScope (@base))
+ if (IsMethodNeededByTypeDueToPreservedScope (@base))
return true;
}
@@ -3110,7 +3137,7 @@ namespace Mono.Linker.Steps
protected virtual IEnumerable<MethodDefinition> 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 7b604a38a..74ea1c72d 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 @@ namespace ILLink.RoslynAnalyzer.Tests.Inheritance
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 000000000..655198709
--- /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 6b2cbd511..1c4a08112 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 @@ using Mono.Linker.Tests.Cases.Expectations.Metadata;
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 000000000..f9d54d009
--- /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 000000000..0f31e8277
--- /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 8cc979367..1534573ea 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]
@@ -172,6 +179,204 @@ namespace Mono.Linker.Tests.Cases.Libraries
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 8aeb92da8..991c1860e 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs
@@ -234,7 +234,7 @@ namespace Mono.Linker.Tests.TestCasesRunner
#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