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:
-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" />