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:
authorMichael Voorhees <michaelv@unity3d.com>2019-02-09 00:05:58 +0300
committerMarek Safar <marek.safar@gmail.com>2019-02-15 01:48:03 +0300
commite64148792193bf7d706428a64632ebf7f8023d3b (patch)
treeaed858919bc7ceca1117337b22323fbc564fe89f
parent6b87e44f8534486e46f272cfecb3048424acd676 (diff)
Fix an invalid IL bug with interface sweeping
If a type can be on the stack then we need to keep the interface implementation on that type even if the type is never instantiated. I think we can get away with only doing this when the using of the type and the interface are within the same body. Once beyond the body, there won't be invalid IL. Casting is similar, see `ObjectHardCastedToInterface`
-rw-r--r--linker/Linker.Steps/MarkStep.cs22
-rw-r--r--linker/Linker.Steps/TypeMapStep.cs25
-rw-r--r--linker/Linker/Annotations.cs13
-rw-r--r--linker/Linker/MethodBodyScanner.cs119
-rw-r--r--linker/Linker/TypeDefinitionExtensions.cs21
-rw-r--r--linker/Mono.Linker.csproj6
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideThatAlsoFulfilsInterface.cs8
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericType.cs22
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericWithConstraintDoesNotCauseOtherTypesToKeepInterface.cs41
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/LocalDowncastDoesNotCuaseOtherTypesToKeepInterface.cs47
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/ObjectHardCastedToInterface.cs40
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayPassedAsParameter.cs25
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayWithIndexAssignedToReturnValue.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/FieldDowncastedToInterface.cs32
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericType.cs30
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint.cs24
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint2.cs28
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint3.cs58
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/InterfaceOnMultipleBases.cs42
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalDowncastedToInterface.cs27
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameter.cs25
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGeneric.cs25
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint.cs25
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint2.cs32
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ReturnValueDowncastedToInterface.cs30
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj18
26 files changed, 807 insertions, 4 deletions
diff --git a/linker/Linker.Steps/MarkStep.cs b/linker/Linker.Steps/MarkStep.cs
index fb06bc70c..a42c5facd 100644
--- a/linker/Linker.Steps/MarkStep.cs
+++ b/linker/Linker.Steps/MarkStep.cs
@@ -266,7 +266,7 @@ namespace Mono.Linker.Steps {
// We don't need to mark overrides until it is possible that the type could be instantiated
// Note : The base type is interface check should be removed once we have base type sweeping
- if (!isInstantiated && @base.DeclaringType.IsInterface)
+ if (@base.DeclaringType.IsInterface && !isInstantiated && !IsInterfaceImplementationMarked (method.DeclaringType, @base.DeclaringType))
return;
if (!isInstantiated && !@base.IsAbstract)
@@ -276,6 +276,11 @@ namespace Mono.Linker.Steps {
ProcessVirtualMethod (method);
}
+ bool IsInterfaceImplementationMarked (TypeDefinition type, TypeDefinition interfaceType)
+ {
+ return type.HasInterface (@interfaceType, out InterfaceImplementation implementation) && Annotations.IsMarked (implementation);
+ }
+
void MarkMarshalSpec (IMarshalInfoProvider spec)
{
if (!spec.HasMarshalInfo)
@@ -2004,6 +2009,8 @@ namespace Mono.Linker.Steps {
foreach (Instruction instruction in body.Instructions)
MarkInstruction (instruction);
+ MarkInterfacesNeededByBodyStack (body);
+
MarkThingsUsedViaReflection (body);
PostMarkMethodBody (body);
@@ -2011,6 +2018,19 @@ namespace Mono.Linker.Steps {
partial void PostMarkMethodBody (MethodBody body);
+ void MarkInterfacesNeededByBodyStack (MethodBody body)
+ {
+ // If a type could be on the stack in the body and an interface it implements could be on the stack on the body
+ // then we need to mark that interface implementation. When this occurs it is not safe to remove the interface implementation from the type
+ // even if the type is never instantiated
+ var implementations = MethodBodyScanner.GetReferencedInterfaces (_context.Annotations, body);
+ if (implementations == null)
+ return;
+
+ foreach (var implementation in implementations)
+ MarkInterfaceImplementation (implementation);
+ }
+
protected virtual void MarkThingsUsedViaReflection (MethodBody body)
{
MarkSomethingUsedViaReflection ("GetConstructor", MarkConstructorsUsedViaReflection, body.Instructions);
diff --git a/linker/Linker.Steps/TypeMapStep.cs b/linker/Linker.Steps/TypeMapStep.cs
index 44e882330..4189e65a8 100644
--- a/linker/Linker.Steps/TypeMapStep.cs
+++ b/linker/Linker.Steps/TypeMapStep.cs
@@ -44,6 +44,7 @@ namespace Mono.Linker.Steps {
{
MapVirtualMethods (type);
MapInterfaceMethodsInTypeHierarchy (type);
+ MapBaseTypeHierarchy (type);
if (!type.HasNestedTypes)
return;
@@ -123,6 +124,30 @@ namespace Mono.Linker.Steps {
}
}
+ void MapBaseTypeHierarchy (TypeDefinition type)
+ {
+ if (!type.IsClass)
+ return;
+
+ var bases = new List<TypeDefinition> ();
+ var current = type.BaseType;
+
+ while (current != null) {
+ var resolved = current.Resolve ();
+ if (resolved == null)
+ break;
+
+ // Exclude Object. That's implied and adding it to the list will just lead to lots of extra unnecessary processing
+ if (resolved.BaseType == null)
+ break;
+
+ bases.Add (resolved);
+ current = resolved.BaseType;
+ }
+
+ Annotations.SetClassHierarchy (type, bases);
+ }
+
void AnnotateMethods (MethodDefinition @base, MethodDefinition @override)
{
Annotations.AddBaseMethod (@override, @base);
diff --git a/linker/Linker/Annotations.cs b/linker/Linker/Annotations.cs
index 80b90e0b5..488ce9cc4 100644
--- a/linker/Linker/Annotations.cs
+++ b/linker/Linker/Annotations.cs
@@ -48,6 +48,7 @@ namespace Mono.Linker {
protected readonly Dictionary<MethodDefinition, List<MethodDefinition>> override_methods = new Dictionary<MethodDefinition, List<MethodDefinition>> ();
protected readonly Dictionary<MethodDefinition, List<MethodDefinition>> base_methods = new Dictionary<MethodDefinition, List<MethodDefinition>> ();
protected readonly Dictionary<AssemblyDefinition, ISymbolReader> symbol_readers = new Dictionary<AssemblyDefinition, ISymbolReader> ();
+ protected readonly Dictionary<TypeDefinition, List<TypeDefinition>> class_type_base_hierarchy = new Dictionary<TypeDefinition, List<TypeDefinition>> ();
protected readonly Dictionary<object, Dictionary<IMetadataTokenProvider, object>> custom_annotations = new Dictionary<object, Dictionary<IMetadataTokenProvider, object>> ();
protected readonly Dictionary<AssemblyDefinition, HashSet<string>> resources_to_remove = new Dictionary<AssemblyDefinition, HashSet<string>> ();
@@ -355,5 +356,17 @@ namespace Mono.Linker {
return marked_types_with_cctor.Add (type);
}
+ public void SetClassHierarchy (TypeDefinition type, List<TypeDefinition> bases)
+ {
+ class_type_base_hierarchy [type] = bases;
+ }
+
+ public List<TypeDefinition> GetClassHierarchy (TypeDefinition type)
+ {
+ if (class_type_base_hierarchy.TryGetValue (type, out List<TypeDefinition> bases))
+ return bases;
+
+ return null;
+ }
}
}
diff --git a/linker/Linker/MethodBodyScanner.cs b/linker/Linker/MethodBodyScanner.cs
new file mode 100644
index 000000000..f875ad162
--- /dev/null
+++ b/linker/Linker/MethodBodyScanner.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Mono.Linker {
+ public static class MethodBodyScanner {
+ public static IEnumerable<InterfaceImplementation> GetReferencedInterfaces (AnnotationStore annotations, MethodBody body)
+ {
+ var possibleStackTypes = AllPossibleStackTypes (body.Method);
+ if (possibleStackTypes.Count == 0)
+ return null;
+
+ var interfaceTypes = possibleStackTypes.Where (t => t.IsInterface).ToArray ();
+ if (interfaceTypes.Length == 0)
+ return null;
+
+ var interfaceImplementations = new HashSet<InterfaceImplementation> ();
+
+ // If a type could be on the stack in the body and an interface it implements could be on the stack on the body
+ // then we need to mark that interface implementation. When this occurs it is not safe to remove the interface implementation from the type
+ // even if the type is never instantiated
+ foreach (var type in possibleStackTypes) {
+ // We only sweep interfaces on classes so that's why we only care about classes
+ if (!type.IsClass)
+ continue;
+
+ AddMatchingInterfaces (interfaceImplementations, type, interfaceTypes);
+ var bases = annotations.GetClassHierarchy (type);
+ foreach (var @base in bases) {
+ AddMatchingInterfaces (interfaceImplementations, @base, interfaceTypes);
+ }
+ }
+
+ return interfaceImplementations;
+ }
+
+ static HashSet<TypeDefinition> AllPossibleStackTypes (MethodDefinition method)
+ {
+ if (!method.HasBody)
+ throw new ArgumentException();
+
+ var body = method.Body;
+ var types = new HashSet<TypeDefinition> ();
+
+ foreach (VariableDefinition var in body.Variables)
+ AddIfResolved (types, var.VariableType);
+
+ foreach (ExceptionHandler eh in body.ExceptionHandlers) {
+ if (eh.HandlerType == ExceptionHandlerType.Catch) {
+ AddIfResolved (types, eh.CatchType);
+ }
+ }
+
+ foreach (Instruction instruction in body.Instructions) {
+ if (instruction.Operand is FieldReference fieldReference) {
+ AddIfResolved (types, fieldReference.Resolve ()?.FieldType);
+ } else if (instruction.Operand is MethodReference methodReference) {
+ if (methodReference is GenericInstanceMethod genericInstanceMethod)
+ AddFromGenericInstance (types, genericInstanceMethod);
+
+ if (methodReference.DeclaringType is GenericInstanceType genericInstanceType)
+ AddFromGenericInstance (types, genericInstanceType);
+
+ var resolvedMethod = methodReference.Resolve ();
+ if (resolvedMethod != null) {
+ if (resolvedMethod.HasParameters) {
+ foreach (var param in resolvedMethod.Parameters)
+ AddIfResolved (types, param.ParameterType);
+ }
+
+ AddFromGenericParameterProvider (types, resolvedMethod);
+ AddFromGenericParameterProvider (types, resolvedMethod.DeclaringType);
+ AddIfResolved (types, resolvedMethod.ReturnType);
+ }
+ }
+ }
+
+ return types;
+ }
+
+ static void AddMatchingInterfaces (HashSet<InterfaceImplementation> results, TypeDefinition type, TypeDefinition [] interfaceTypes)
+ {
+ foreach (var interfaceType in interfaceTypes) {
+ if (type.HasInterface (interfaceType, out InterfaceImplementation implementation))
+ results.Add (implementation);
+ }
+ }
+
+ static void AddFromGenericInstance (HashSet<TypeDefinition> set, IGenericInstance instance)
+ {
+ if (!instance.HasGenericArguments)
+ return;
+
+ foreach (var genericArgument in instance.GenericArguments)
+ AddIfResolved (set, genericArgument);
+ }
+
+ static void AddFromGenericParameterProvider (HashSet<TypeDefinition> set, IGenericParameterProvider provider)
+ {
+ if (!provider.HasGenericParameters)
+ return;
+
+ foreach (var genericParameter in provider.GenericParameters) {
+ foreach (var constraint in genericParameter.Constraints)
+ AddIfResolved (set, constraint);
+ }
+ }
+
+ static void AddIfResolved (HashSet<TypeDefinition> set, TypeReference item)
+ {
+ var resolved = item.Resolve ();
+ if (resolved == null)
+ return;
+ set.Add (resolved);
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Linker/TypeDefinitionExtensions.cs b/linker/Linker/TypeDefinitionExtensions.cs
new file mode 100644
index 000000000..f94e340c3
--- /dev/null
+++ b/linker/Linker/TypeDefinitionExtensions.cs
@@ -0,0 +1,21 @@
+using Mono.Cecil;
+
+namespace Mono.Linker {
+ public static class TypeDefinitionExtensions {
+ public static bool HasInterface (this TypeDefinition type, TypeDefinition interfaceType, out InterfaceImplementation implementation)
+ {
+ implementation = null;
+ if (!type.HasInterfaces)
+ return false;
+
+ foreach (var iface in type.Interfaces) {
+ if (iface.InterfaceType.Resolve () == interfaceType) {
+ implementation = iface;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Mono.Linker.csproj b/linker/Mono.Linker.csproj
index cd547ca51..2b82f3838 100644
--- a/linker/Mono.Linker.csproj
+++ b/linker/Mono.Linker.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
<!--
TODO: Remove this workaround once supported.
@@ -65,6 +65,7 @@
<Compile Include="Linker.Steps\RegenerateGuidStep.cs" />
<Compile Include="Linker.Steps\LoadI18nAssemblies.cs" />
<Compile Include="Linker.Steps\RemoveSecurityStep.cs" />
+ <Compile Include="Linker\MethodBodyScanner.cs" />
<Compile Include="Linker\IXApiVisitor.cs" />
<Compile Include="Linker\I18nAssemblies.cs" />
<Compile Include="Linker.Steps\IStep.cs" />
@@ -91,6 +92,7 @@
<Compile Include="Linker\MethodAction.cs" />
<Compile Include="Linker\MethodReferenceExtensions.cs" />
<Compile Include="Linker\Pipeline.cs" />
+ <Compile Include="Linker\TypeDefinitionExtensions.cs" />
<Compile Include="Linker\TypePreserve.cs" />
<Compile Include="Linker\TypeReferenceExtensions.cs" />
<Compile Include="Linker\TypeNameParser.cs" />
@@ -133,4 +135,4 @@
<Name>Mono.Cecil.Pdb</Name>
</ProjectReference>
</ItemGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideThatAlsoFulfilsInterface.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideThatAlsoFulfilsInterface.cs
index c909a70e6..428310dad 100644
--- a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideThatAlsoFulfilsInterface.cs
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideThatAlsoFulfilsInterface.cs
@@ -6,7 +6,13 @@ namespace Mono.Linker.Tests.Cases.Inheritance.AbstractClasses.NoKeptCtor.Overrid
{
Base b = HelperToMarkFooAndRequireBase ();
b.Method ();
-
+
+ MethodToUseTheInterface ();
+ }
+
+ [Kept]
+ static void MethodToUseTheInterface ()
+ {
// Now use the interface method so that it is kept
IFoo f = new Bar ();
f.Method ();
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericType.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericType.cs
new file mode 100644
index 000000000..b6dff2fde
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericType.cs
@@ -0,0 +1,22 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtor {
+ public class GenericType {
+ public static void Main ()
+ {
+ object o = new Bar<Foo> ();
+ }
+
+ [Kept]
+ [KeptMember(".ctor()")]
+ class Bar<T> {
+ }
+
+ [Kept]
+ class Foo : IFoo {
+ }
+
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericWithConstraintDoesNotCauseOtherTypesToKeepInterface.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericWithConstraintDoesNotCauseOtherTypesToKeepInterface.cs
new file mode 100644
index 000000000..7255cac2c
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/GenericWithConstraintDoesNotCauseOtherTypesToKeepInterface.cs
@@ -0,0 +1,41 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtor {
+ public class GenericWithConstraintDoesNotCauseOtherTypesToKeepInterface {
+ public static void Main ()
+ {
+ Foo f = null;
+ Helper (f);
+ OtherMethodToDoStuff ();
+ }
+
+ [Kept]
+ static void Helper<T> (T f) where T : IFoo
+ {
+ }
+
+ [Kept]
+ static void OtherMethodToDoStuff ()
+ {
+ HelperToUseFoo2 (null);
+ }
+
+ [Kept]
+ static void HelperToUseFoo2 (Foo2 f)
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ class Foo2 : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/LocalDowncastDoesNotCuaseOtherTypesToKeepInterface.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/LocalDowncastDoesNotCuaseOtherTypesToKeepInterface.cs
new file mode 100644
index 000000000..00ad89fd2
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/LocalDowncastDoesNotCuaseOtherTypesToKeepInterface.cs
@@ -0,0 +1,47 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtor {
+ public class LocalDowncastDoesNotCuaseOtherTypesToKeepInterface {
+ public static void Main ()
+ {
+ Foo f = null;
+ IFoo i = f;
+ i.Method ();
+ DoOtherStuff ();
+ }
+
+ [Kept]
+ static void DoOtherStuff ()
+ {
+ HelperToUseBar (null);
+ }
+
+ [Kept]
+ static void HelperToUseBar (Bar arg)
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ [Kept] // TODO : It should be safe to stub this. It can't actually be called because no instance of Foo ever exists
+ public void Method ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IFoo {
+ [Kept]
+ void Method ();
+ }
+
+ [Kept]
+ class Bar : IFoo
+ {
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/ObjectHardCastedToInterface.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/ObjectHardCastedToInterface.cs
new file mode 100644
index 000000000..84b9b6c16
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/ObjectHardCastedToInterface.cs
@@ -0,0 +1,40 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtor {
+ public class ObjectHardCastedToInterface {
+ public static void Main ()
+ {
+ object o = GetAnObject ();
+ IFoo i = (IFoo)o;
+ UseAnIFoo (i);
+
+ // Here to mark Foo so that we can verify the interface is removed
+ Foo.Helper ();
+ }
+
+ [Kept]
+ static object GetAnObject ()
+ {
+ return null;
+ }
+
+ [Kept]
+ static void UseAnIFoo (IFoo arg)
+ {
+ }
+
+ [Kept]
+ class Foo : IFoo
+ {
+ [Kept]
+ public static void Helper ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IFoo
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayPassedAsParameter.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayPassedAsParameter.cs
new file mode 100644
index 000000000..0a9aacc0c
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayPassedAsParameter.cs
@@ -0,0 +1,25 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class LocalArrayPassedAsParameter {
+ public static void Main ()
+ {
+ Foo [] arr = null;
+ Helper (arr);
+ }
+
+ [Kept]
+ static void Helper (IFoo[] f)
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayWithIndexAssignedToReturnValue.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayWithIndexAssignedToReturnValue.cs
new file mode 100644
index 000000000..179b7577b
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ArrayWithIndexAssignedToReturnValue.cs
@@ -0,0 +1,26 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class ArrayWithIndexAssignedToReturnValue {
+ public static void Main ()
+ {
+ IFoo [] arr = new IFoo [5];
+ arr [0] = GetAFoo ();
+ }
+
+ [Kept]
+ static Foo GetAFoo ()
+ {
+ return null;
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/FieldDowncastedToInterface.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/FieldDowncastedToInterface.cs
new file mode 100644
index 000000000..84ff1a1c7
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/FieldDowncastedToInterface.cs
@@ -0,0 +1,32 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class FieldDowncastedToInterface {
+ [Kept]
+ private static Foo f;
+ [Kept]
+ private static IFoo i;
+
+ public static void Main ()
+ {
+ f = null;
+ i = f;
+ i.Method ();
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ [Kept] // TODO : It should be safe to stub this. It can't actually be called because no instance of Foo ever exists
+ public void Method ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IFoo {
+ [Kept]
+ void Method ();
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericType.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericType.cs
new file mode 100644
index 000000000..7e8e8ffa9
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericType.cs
@@ -0,0 +1,30 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class GenericType {
+ public static void Main ()
+ {
+ Foo f = null;
+ Bar<IFoo> o = new Bar<IFoo> ();
+ o.Method (f);
+ }
+
+ [Kept]
+ [KeptMember(".ctor()")]
+ class Bar<T> {
+ [Kept]
+ public void Method (T arg)
+ {
+ }
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint.cs
new file mode 100644
index 000000000..48051732a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint.cs
@@ -0,0 +1,24 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class GenericTypeWithConstraint {
+ public static void Main ()
+ {
+ object o = new Bar<Foo> ();
+ }
+
+ [Kept]
+ [KeptMember(".ctor()")]
+ class Bar<T> where T : IFoo {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint2.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint2.cs
new file mode 100644
index 000000000..0fb889ae8
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint2.cs
@@ -0,0 +1,28 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class GenericTypeWithConstraint2 {
+ public static void Main ()
+ {
+ Foo f = null;
+ Bar<Foo>.Helper (f);
+ }
+
+ [Kept]
+ static class Bar<T> where T : IFoo {
+ [Kept]
+ public static void Helper (T arg)
+ {
+ }
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint3.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint3.cs
new file mode 100644
index 000000000..bc170287e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/GenericTypeWithConstraint3.cs
@@ -0,0 +1,58 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class GenericTypeWithConstraint3 {
+ public static void Main ()
+ {
+ Foo f = null;
+ Bar b = null;
+ Bar<BaseFoo2, BaseBar2>.Helper (f, b);
+ }
+
+ [Kept]
+ static class Bar<T, K> where T : IFoo where K : IBar {
+ [Kept]
+ public static void Helper (T arg, K arg2)
+ {
+ }
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ abstract class BaseFoo : IFoo {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (BaseFoo))]
+ abstract class BaseFoo2 : BaseFoo {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IBar))]
+ abstract class BaseBar : IBar {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (BaseBar))]
+ abstract class BaseBar2 : BaseBar {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (BaseFoo2))]
+ class Foo : BaseFoo2 {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (BaseBar2))]
+ class Bar : BaseBar2 {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+
+ [Kept]
+ interface IBar {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/InterfaceOnMultipleBases.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/InterfaceOnMultipleBases.cs
new file mode 100644
index 000000000..6b303e24f
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/InterfaceOnMultipleBases.cs
@@ -0,0 +1,42 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class InterfaceOnMultipleBases {
+ public static void Main ()
+ {
+ Foo f = null;
+ Helper (f);
+ }
+
+ [Kept]
+ static void Helper (IFoo f)
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Base : IFoo {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ [KeptInterface (typeof (IFoo))]
+ class Base2 : Base, IFoo {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base2))]
+ class Base3 : Base2 {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base3))]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : Base3, IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalDowncastedToInterface.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalDowncastedToInterface.cs
new file mode 100644
index 000000000..dc63d99a3
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalDowncastedToInterface.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class LocalDowncastedToInterface {
+ public static void Main ()
+ {
+ Foo f = null;
+ IFoo i = f;
+ i.Method ();
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ [Kept] // TODO : It should be safe to stub this. It can't actually be called because no instance of Foo ever exists
+ public void Method ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IFoo {
+ [Kept]
+ void Method ();
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameter.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameter.cs
new file mode 100644
index 000000000..5338cc6ba
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameter.cs
@@ -0,0 +1,25 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class LocalPassedAsParameter {
+ public static void Main ()
+ {
+ Foo f = null;
+ Helper (f);
+ }
+
+ [Kept]
+ static void Helper (IFoo f)
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGeneric.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGeneric.cs
new file mode 100644
index 000000000..475ac098a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGeneric.cs
@@ -0,0 +1,25 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class LocalPassedAsParameterToGeneric {
+ public static void Main ()
+ {
+ Foo f = null;
+ Helper<IFoo>(f);
+ }
+
+ [Kept]
+ static void Helper <T> (T f)
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint.cs
new file mode 100644
index 000000000..e00229264
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint.cs
@@ -0,0 +1,25 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class LocalPassedAsParameterToGenericWithConstraint {
+ public static void Main ()
+ {
+ Foo f = null;
+ Helper (f);
+ }
+
+ [Kept]
+ static void Helper<T> (T f) where T : IFoo
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint2.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint2.cs
new file mode 100644
index 000000000..cecf742e4
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/LocalPassedAsParameterToGenericWithConstraint2.cs
@@ -0,0 +1,32 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class LocalPassedAsParameterToGenericWithConstraint2 {
+ public static void Main ()
+ {
+ Foo f = null;
+ Foo2 f2 = null;
+ Helper (f, f2);
+ }
+
+ [Kept]
+ static void Helper<T> (T f, Foo2 arg2) where T : IFoo
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))] // technically this can be removed, but it would require more complex knowledge of the stack to do so
+ class Foo2 : IFoo {
+ }
+
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ReturnValueDowncastedToInterface.cs b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ReturnValueDowncastedToInterface.cs
new file mode 100644
index 000000000..0aef967a5
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtorButInterfaceNeeded/ReturnValueDowncastedToInterface.cs
@@ -0,0 +1,30 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded {
+ public class ReturnValueDowncastedToInterface {
+ public static void Main ()
+ {
+ UseAnIFoo (GetAFoo ());
+ }
+
+ [Kept]
+ static Foo GetAFoo ()
+ {
+ return null;
+ }
+
+ [Kept]
+ static void UseAnIFoo (IFoo arg)
+ {
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ }
+
+ [Kept]
+ interface IFoo {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj b/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
index 70d0a755d..27c913108 100644
--- a/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
@@ -220,13 +220,31 @@
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoInstanceCtor\NoInstanceCtorAndTypePreserveMethods.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoInstanceCtor\NoInstanceCtorAndTypePreserveMethodsWithInterfacesMarked.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoInstanceCtor\NoInstanceCtorAndTypePreserveNone.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\ArrayWithIndexAssignedToReturnValue.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\ArrayPassedAsParameter.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\FieldDowncastedToInterface.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\GenericType.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\GenericTypeWithConstraint2.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\GenericTypeWithConstraint3.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\InterfaceOnMultipleBases.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\LocalDowncastedToInterface.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\LocalPassedAsParameter.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\LocalPassedAsParameterToGeneric.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\LocalPassedAsParameterToGenericWithConstraint.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\LocalPassedAsParameterToGenericWithConstraint2.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\ReturnValueDowncastedToInterface.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtorButInterfaceNeeded\GenericTypeWithConstraint.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\ComInterfaceTypeRemovedWhenOnlyUsedByClassWithOnlyStaticMethod.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\ExplicitInterfaceCanBeRemovedFromClassWithOnlyStaticMethodUsed.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\GenericType.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\InterfaceCanBeRemovedFromClassWithOnlyStaticMethodUsed.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\InterfaceCanBeRemovedFromClassWithOnlyStaticMethodUsedWithCctor.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\InterfaceFromCopiedAssemblyCanBeRemoved.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\InterfaceTypeRemovedWhenOnlyUsedByClassWithOnlyStaticMethod.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\InterfaceTypeRemovedWhenOnlyUsedByClassWithOnlyStaticMethodMultiple.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\LocalDowncastDoesNotCuaseOtherTypesToKeepInterface.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\GenericWithConstraintDoesNotCauseOtherTypesToKeepInterface.cs" />
+ <Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\ObjectHardCastedToInterface.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\PreserveDependencyPreservesInterfaceMethod.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\UnusedTypeWithPreserveFields.cs" />
<Compile Include="Inheritance.Interfaces\OnReferenceType\NoKeptCtor\UnusedTypeWithPreserveMethods.cs" />