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--src/linker/Linker.Steps/CodeRewriterStep.cs7
-rw-r--r--src/linker/Linker.Steps/MarkStep.cs67
-rw-r--r--src/linker/Linker.Steps/RemoveFeaturesStep.cs8
-rw-r--r--src/linker/Linker/BCL.cs11
-rw-r--r--src/linker/Linker/Driver.cs4
-rw-r--r--src/linker/Linker/LinkContext.cs5
-rw-r--r--src/linker/Linker/MethodBodyScanner.cs43
-rw-r--r--test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSource.cs5
-rw-r--r--test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSourceEmptyBody.cs75
-rw-r--r--test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/Excluded.cs5
-rw-r--r--test/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideOfAbstractIsKeptNonEmpty.cs48
-rw-r--r--test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/UnusedTypeHasExplicitInterfacePropertyPreservedViaXml.cs3
-rw-r--r--test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.cs29
-rw-r--r--test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.xml4
-rw-r--r--test/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs2
-rw-r--r--test/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs2
-rw-r--r--test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj35
-rw-r--r--test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs5
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs16
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflectionWithDefaultBindingFlags.cs44
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/MightKeepExtraThings.cs4
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/CanDisableLazyBodyMarking.cs32
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssembly.cs18
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssemblyNoInstanceCtor.il63
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly.cs23
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly2.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly.cs23
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly2.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/ExplicitInstructionCheck.cs35
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/InterfaceMethod.cs38
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibrary.cs23
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibraryNoInstanceCtor.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/MixOfMethods.cs148
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingEmpty.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnDouble.cs28
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFalse.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFloat.cs28
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnInt.cs90
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnLong.cs28
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnNull.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnTrue.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAVirtual.cs44
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal.cs46
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal2.cs53
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal3.cs40
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodWhenInterfaceRemoved2.cs58
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbed.cs39
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbedWithUnusedInterface.cs44
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleGetter.cs22
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleMethod.cs30
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleSetter.cs22
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.cs23
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.xml7
-rw-r--r--test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs31
-rw-r--r--test/Mono.Linker.Tests/TestCases/TestDatabase.cs5
-rw-r--r--test/Mono.Linker.Tests/TestCases/TestSuites.cs6
56 files changed, 1594 insertions, 64 deletions
diff --git a/src/linker/Linker.Steps/CodeRewriterStep.cs b/src/linker/Linker.Steps/CodeRewriterStep.cs
index a7029936b..8d2d7c8a7 100644
--- a/src/linker/Linker.Steps/CodeRewriterStep.cs
+++ b/src/linker/Linker.Steps/CodeRewriterStep.cs
@@ -45,16 +45,17 @@ namespace Mono.Linker.Steps {
}
}
- void RewriteBodyToLinkedAway (MethodDefinition method)
+ protected virtual void RewriteBodyToLinkedAway (MethodDefinition method)
{
method.ImplAttributes &= ~(MethodImplAttributes.AggressiveInlining | MethodImplAttributes.Synchronized);
method.ImplAttributes |= MethodImplAttributes.NoInlining;
method.Body = CreateThrowLinkedAwayBody (method);
+
ClearDebugInformation (method);
}
- void RewriteBodyToStub (MethodDefinition method)
+ protected virtual void RewriteBodyToStub (MethodDefinition method)
{
if (!method.IsIL)
throw new NotImplementedException ();
@@ -64,7 +65,7 @@ namespace Mono.Linker.Steps {
ClearDebugInformation (method);
}
- void RewriteBodyToFalse (MethodDefinition method)
+ protected virtual void RewriteBodyToFalse (MethodDefinition method)
{
if (!method.IsIL)
throw new NotImplementedException ();
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs
index d73fd3693..5b7d48ff2 100644
--- a/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/linker/Linker.Steps/MarkStep.cs
@@ -46,6 +46,7 @@ namespace Mono.Linker.Steps {
protected Queue<AttributeProviderPair> _assemblyLevelAttributes;
protected Queue<AttributeProviderPair> _lateMarkedAttributes;
protected List<TypeDefinition> _typesWithInterfaces;
+ protected List<MethodBody> _unreachableBodies;
public AnnotationStore Annotations {
get { return _context.Annotations; }
@@ -64,6 +65,7 @@ namespace Mono.Linker.Steps {
_assemblyLevelAttributes = new Queue<AttributeProviderPair> ();
_lateMarkedAttributes = new Queue<AttributeProviderPair> ();
_typesWithInterfaces = new List<TypeDefinition> ();
+ _unreachableBodies = new List<MethodBody> ();
}
public virtual void Process (LinkContext context)
@@ -72,6 +74,7 @@ namespace Mono.Linker.Steps {
Initialize ();
Process ();
+ Complete ();
}
void Initialize ()
@@ -93,6 +96,13 @@ namespace Mono.Linker.Steps {
}
}
+ void Complete ()
+ {
+ foreach (var body in _unreachableBodies) {
+ Annotations.SetAction (body.Method, MethodAction.ConvertToThrow);
+ }
+ }
+
void InitializeType (TypeDefinition type)
{
if (type.HasNestedTypes) {
@@ -188,6 +198,7 @@ namespace Mono.Linker.Steps {
ProcessQueue ();
ProcessVirtualMethods ();
ProcessMarkedTypesWithInterfaces ();
+ ProcessPendingBodies ();
DoAdditionalProcessing ();
}
@@ -242,6 +253,17 @@ namespace Mono.Linker.Steps {
}
}
+ void ProcessPendingBodies ()
+ {
+ for (int i = 0; i < _unreachableBodies.Count; i++) {
+ var body = _unreachableBodies [i];
+ if (Annotations.IsInstantiated (body.Method.DeclaringType)) {
+ MarkMethodBody (body);
+ _unreachableBodies.RemoveAt (i--);
+ }
+ }
+ }
+
void ProcessVirtualMethod (MethodDefinition method)
{
var overrides = Annotations.GetOverrides (method);
@@ -1919,23 +1941,28 @@ namespace Mono.Linker.Steps {
break;
case MethodAction.ConvertToThrow:
- if (_context.MarkedKnownMembers.NotSupportedExceptionCtorString != null)
- break;
+ MarkAndCacheNotSupportedCtorString ();
+ break;
+ }
+ }
- var nse = BCL.FindPredefinedType ("System", "NotSupportedException", _context);
- if (nse == null)
- throw new NotSupportedException ("Missing predefined 'System.NotSupportedException' type");
+ void MarkAndCacheNotSupportedCtorString ()
+ {
+ if (_context.MarkedKnownMembers.NotSupportedExceptionCtorString != null)
+ return;
- MarkType (nse);
+ var nse = BCL.FindPredefinedType ("System", "NotSupportedException", _context);
+ if (nse == null)
+ throw new NotSupportedException ("Missing predefined 'System.NotSupportedException' type");
- var nseCtor = MarkMethodIf (nse.Methods, KnownMembers.IsNotSupportedExceptionCtorString);
- if (nseCtor == null)
- throw new MarkException ($"Could not find constructor on '{nse.FullName}'");
+ MarkType (nse);
- _context.MarkedKnownMembers.NotSupportedExceptionCtorString = nseCtor;
- break;
- }
- }
+ var nseCtor = MarkMethodIf (nse.Methods, KnownMembers.IsNotSupportedExceptionCtorString);
+ if (nseCtor == null)
+ throw new MarkException ($"Could not find constructor on '{nse.FullName}'");
+
+ _context.MarkedKnownMembers.NotSupportedExceptionCtorString = nseCtor;
+ }
void MarkBaseMethods (MethodDefinition method)
{
@@ -2068,6 +2095,12 @@ namespace Mono.Linker.Steps {
protected virtual void MarkMethodBody (MethodBody body)
{
+ if (_context.IsOptimizationEnabled (CodeOptimizations.UnreachableBodies) && IsUnreachableBody (body)) {
+ MarkAndCacheNotSupportedCtorString ();
+ _unreachableBodies.Add (body);
+ return;
+ }
+
foreach (VariableDefinition var in body.Variables)
MarkType (var.VariableType);
@@ -2085,6 +2118,14 @@ namespace Mono.Linker.Steps {
PostMarkMethodBody (body);
}
+ bool IsUnreachableBody (MethodBody body)
+ {
+ return !body.Method.IsStatic
+ && !Annotations.IsInstantiated (body.Method.DeclaringType)
+ && MethodBodyScanner.IsWorthConvertingToThrow (body);
+ }
+
+
partial void PostMarkMethodBody (MethodBody body);
void MarkInterfacesNeededByBodyStack (MethodBody body)
diff --git a/src/linker/Linker.Steps/RemoveFeaturesStep.cs b/src/linker/Linker.Steps/RemoveFeaturesStep.cs
index 225472d4f..14bb889fa 100644
--- a/src/linker/Linker.Steps/RemoveFeaturesStep.cs
+++ b/src/linker/Linker.Steps/RemoveFeaturesStep.cs
@@ -100,7 +100,8 @@ namespace Mono.Linker.Steps
continue;
}
- annotations.SetAction (method, MethodAction.ConvertToThrow);
+ if (MethodBodyScanner.IsWorthConvertingToThrow (method.Body))
+ annotations.SetAction (method, MethodAction.ConvertToThrow);
}
}
@@ -149,7 +150,7 @@ namespace Mono.Linker.Steps
continue;
}
- if (!skip)
+ if (!skip && MethodBodyScanner.IsWorthConvertingToThrow (method.Body))
annotations.SetAction (method, MethodAction.ConvertToThrow);
}
}
@@ -166,7 +167,8 @@ namespace Mono.Linker.Steps
{
foreach (var method in type.Methods)
{
- annotations.SetAction(method, MethodAction.ConvertToThrow);
+ if (MethodBodyScanner.IsWorthConvertingToThrow (method.Body))
+ annotations.SetAction(method, MethodAction.ConvertToThrow);
}
}
diff --git a/src/linker/Linker/BCL.cs b/src/linker/Linker/BCL.cs
index 1c75a056d..9d26c060f 100644
--- a/src/linker/Linker/BCL.cs
+++ b/src/linker/Linker/BCL.cs
@@ -65,9 +65,14 @@ namespace Mono.Linker
var cache = context.Resolver.AssemblyCache;
AssemblyDefinition corlib;
- if (cache.TryGetValue ("mscorlib", out corlib))
- return corlib.MainModule.GetType (ns, name);
-
+ TypeDefinition type = null;
+ if (cache.TryGetValue ("mscorlib", out corlib)) {
+ type = corlib.MainModule.GetType (ns, name);
+ // The assembly could be a facade with type forwarders, in which case we don't find the type in this assembly.
+ if (type != null)
+ return type;
+ }
+
if (cache.TryGetValue ("System.Private.CoreLib", out corlib))
return corlib.MainModule.GetType (ns, name);
diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs
index 3cca83aaf..02fc7b509 100644
--- a/src/linker/Linker/Driver.cs
+++ b/src/linker/Linker/Driver.cs
@@ -363,6 +363,9 @@ namespace Mono.Linker {
case "overrideremoval":
context.DisabledOptimizations |= CodeOptimizations.OverrideRemoval;
break;
+ case "unreachablebodies":
+ context.DisabledOptimizations |= CodeOptimizations.UnreachableBodies;
+ break;
}
}
}
@@ -522,6 +525,7 @@ namespace Mono.Linker {
Console.WriteLine (" --disable-opt <name> Disable one of the default optimizations");
Console.WriteLine (" beforefieldinit: Unused static fields are removed if there is no static ctor");
Console.WriteLine (" overrideremoval: Overrides of virtual methods on types that are never instantiated are removed");
+ Console.WriteLine (" unreachablebodies: Instance methods that are marked but can never be entered are converted to throws");
Console.WriteLine (" --exclude-feature <name> Any code which has a feature <name> in linked assemblies will be removed");
Console.WriteLine (" com: Support for COM Interop");
Console.WriteLine (" etw: Event Tracing for Windows");
diff --git a/src/linker/Linker/LinkContext.cs b/src/linker/Linker/LinkContext.cs
index 1925eb229..79a0d5ba8 100644
--- a/src/linker/Linker/LinkContext.cs
+++ b/src/linker/Linker/LinkContext.cs
@@ -401,5 +401,10 @@ namespace Mono.Linker {
/// that do not get an instance constructor marked.
/// </summary>
OverrideRemoval = 1 << 1,
+
+ /// <summary>
+ /// Option to disable delaying marking of instance methods until an instance of that type could exist
+ /// </summary>
+ UnreachableBodies = 1 << 2
}
}
diff --git a/src/linker/Linker/MethodBodyScanner.cs b/src/linker/Linker/MethodBodyScanner.cs
index 09d672a93..c9b5d0379 100644
--- a/src/linker/Linker/MethodBodyScanner.cs
+++ b/src/linker/Linker/MethodBodyScanner.cs
@@ -6,6 +6,49 @@ using Mono.Cecil.Cil;
namespace Mono.Linker {
public static class MethodBodyScanner {
+ public static bool IsWorthConvertingToThrow (MethodBody body)
+ {
+ // Some bodies are cheaper size wise to leave alone than to convert to a throw
+ Instruction previousMeaningful = null;
+ int meaningfulCount = 0;
+ foreach (var ins in body.Instructions) {
+ // Handle ignoring noops because because (1) it's a valid case to ignore
+ // and (2) When running the tests on .net core roslyn tosses in no ops
+ // and that leads to a difference in test results between mcs and .net framework csc.
+ if (ins.OpCode.Code == Code.Nop)
+ continue;
+
+ meaningfulCount++;
+
+ if (meaningfulCount == 1 && ins.OpCode.Code == Code.Ret)
+ return false;
+
+ if (meaningfulCount == 2 && ins.OpCode.Code == Code.Ret && previousMeaningful != null) {
+ if (previousMeaningful.OpCode.StackBehaviourPop == StackBehaviour.Pop0) {
+ switch (previousMeaningful.OpCode.StackBehaviourPush) {
+ case StackBehaviour.Pushi:
+ case StackBehaviour.Pushi8:
+ case StackBehaviour.Pushr4:
+ case StackBehaviour.Pushr8:
+ return false;
+ }
+
+ switch (previousMeaningful.OpCode.Code) {
+ case Code.Ldnull:
+ return false;
+ }
+ }
+ }
+
+ if (meaningfulCount >= 2)
+ return true;
+
+ previousMeaningful = ins;
+ }
+
+ return true;
+ }
+
public static IEnumerable<InterfaceImplementation> GetReferencedInterfaces (AnnotationStore annotations, MethodBody body)
{
var possibleStackTypes = AllPossibleStackTypes (body.Method);
diff --git a/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSource.cs b/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSource.cs
index d63d45a7c..5f3ead9a1 100644
--- a/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSource.cs
+++ b/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSource.cs
@@ -50,6 +50,11 @@ namespace Mono.Linker.Tests.Cases.BCLFeatures.ETW {
})]
protected override void OnEventCommand (EventCommandEventArgs command)
{
+ Removed2 ();
+ }
+
+ static void Removed2 ()
+ {
}
[Kept]
diff --git a/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSourceEmptyBody.cs b/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSourceEmptyBody.cs
new file mode 100644
index 000000000..920cb7e91
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/BaseRemovedEventSourceEmptyBody.cs
@@ -0,0 +1,75 @@
+using System.Diagnostics.Tracing;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.BCLFeatures.ETW {
+ [SetupLinkerArgument ("--exclude-feature", "etw")]
+ public class BaseRemovedEventSourceEmptyBody {
+ public static void Main ()
+ {
+ var b = CustomCtorEventSourceEmptyBody.Log.IsEnabled ();
+ if (b)
+ CustomCtorEventSourceEmptyBody.Log.SomeMethod ();
+ }
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (EventSource))]
+ [KeptMember (".ctor()")]
+ [KeptMember (".cctor()")]
+ [EventSource (Name = "MyCompany")]
+ class CustomCtorEventSourceEmptyBody : EventSource {
+ public class Keywords {
+ public const EventKeywords Page = (EventKeywords)1;
+
+ public int Unused;
+ }
+
+ [Kept]
+ public static CustomCtorEventSourceEmptyBody Log = new MyEventSourceBasedOnCustomCtorEventSourceEmptyBody (1);
+
+ [Kept]
+ [ExpectedInstructionSequence (new []
+ {
+ "ldarg.0",
+ "call",
+ "ret",
+ })]
+ public CustomCtorEventSourceEmptyBody (int value)
+ {
+ Removed ();
+ }
+
+ [Kept]
+ protected override void OnEventCommand (EventCommandEventArgs command)
+ {
+ // Not converted to throw because the body is empty
+ }
+
+ [Kept]
+ [ExpectedInstructionSequence (new []
+ {
+ "ldstr",
+ "newobj",
+ "throw",
+ })]
+ [Event (8)]
+ public void SomeMethod ()
+ {
+ Removed ();
+ }
+
+ public void Removed ()
+ {
+ }
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (CustomCtorEventSourceEmptyBody))]
+ class MyEventSourceBasedOnCustomCtorEventSourceEmptyBody : CustomCtorEventSourceEmptyBody {
+ [Kept]
+ public MyEventSourceBasedOnCustomCtorEventSourceEmptyBody (int value) : base (value)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/Excluded.cs b/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/Excluded.cs
index 575a7dec0..20cac269b 100644
--- a/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/Excluded.cs
+++ b/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/Excluded.cs
@@ -41,6 +41,11 @@ namespace Mono.Linker.Tests.Cases.BCLFeatures.ETW {
})]
protected override void OnEventCommand (EventCommandEventArgs command)
{
+ Removed2 ();
+ }
+
+ static void Removed2 ()
+ {
}
[Kept]
diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideOfAbstractIsKeptNonEmpty.cs b/test/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideOfAbstractIsKeptNonEmpty.cs
new file mode 100644
index 000000000..de9030a41
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/Inheritance.AbstractClasses/NoKeptCtor/OverrideRemoval/OverrideOfAbstractIsKeptNonEmpty.cs
@@ -0,0 +1,48 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval {
+ public class OverrideOfAbstractIsKeptNonEmpty {
+ public static void Main ()
+ {
+ Base b = HelperToMarkFooAndRequireBase ();
+ b.Method ();
+ }
+
+ [Kept]
+ static Foo HelperToMarkFooAndRequireBase ()
+ {
+ return null;
+ }
+
+ [Kept]
+ abstract class Base {
+ [Kept]
+ public abstract void Method ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof(Base))]
+ abstract class Base2 : Base {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base2))]
+ abstract class Base3 : Base2 {
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base3))]
+ class Foo : Base3 {
+ [Kept]
+ [ExpectBodyModified]
+ public override void Method ()
+ {
+ Other ();
+ }
+
+ static void Other()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/UnusedTypeHasExplicitInterfacePropertyPreservedViaXml.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/UnusedTypeHasExplicitInterfacePropertyPreservedViaXml.cs
index 191928690..c2116b702 100644
--- a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/UnusedTypeHasExplicitInterfacePropertyPreservedViaXml.cs
+++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/UnusedTypeHasExplicitInterfacePropertyPreservedViaXml.cs
@@ -20,8 +20,7 @@ namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptC
[KeptInterface (typeof (IFoo))]
class A : IBar, IFoo {
[Kept]
- [KeptBackingField]
- int IFoo.Foo { [Kept] get; [Kept] set; }
+ int IFoo.Foo { [Kept] [ExpectBodyModified] get; [Kept] [ExpectBodyModified] set; }
int IBar.Bar { get; set; }
}
diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.cs b/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.cs
index b6e78b255..eb043fb01 100644
--- a/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.cs
+++ b/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.cs
@@ -1,17 +1,22 @@
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Metadata;
-namespace Mono.Linker.Tests.Cases.LinkXml.FeatureExclude {
- [SetupLinkerArgument ("--exclude-feature", "one")]
- public class OnProperty {
- public static void Main ()
- {
- }
+namespace Mono.Linker.Tests.Cases.LinkXml.FeatureExclude {
+ [SetupLinkerArgument ("--exclude-feature", "one")]
+ public class OnProperty {
+ public static void Main ()
+ {
+ new Foo (); // Used to avoid lazy body marking
+ }
- public int FeatureOne { get; set; }
-
- [Kept]
- [KeptBackingField]
- public int FeatureTwo {[Kept] get; [Kept] set; }
- }
+ [Kept]
+ [KeptMember (".ctor()")]
+ class Foo {
+ public int FeatureOne { get; set; }
+
+ [Kept]
+ [KeptBackingField]
+ public int FeatureTwo {[Kept] get; [Kept] set; }
+ }
+ }
}
diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.xml b/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.xml
index 3b2ee6fcb..95d59ecab 100644
--- a/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.xml
+++ b/test/Mono.Linker.Tests.Cases/LinkXml/FeatureExclude/OnProperty.xml
@@ -1,9 +1,9 @@
<linker>
<assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
- <type fullname="Mono.Linker.Tests.Cases.LinkXml.FeatureExclude.OnProperty">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.FeatureExclude.OnProperty/Foo">
<property signature="System.Int32 FeatureOne" accessors="all" feature="one"/>
</type>
- <type fullname="Mono.Linker.Tests.Cases.LinkXml.FeatureExclude.OnProperty">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.FeatureExclude.OnProperty/Foo">
<property signature="System.Int32 FeatureTwo" accessors="all" feature="two"/>
</type>
</assembly>
diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs b/test/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs
index 594b5bd87..b953fdcea 100644
--- a/test/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs
+++ b/test/Mono.Linker.Tests.Cases/LinkXml/UnusedEventPreservedByLinkXmlIsKept.cs
@@ -6,9 +6,11 @@ namespace Mono.Linker.Tests.Cases.LinkXml {
class UnusedEventPreservedByLinkXmlIsKept {
public static void Main ()
{
+ new Unused (); // Used to avoid lazy body marking
}
[Kept]
+ [KeptMember (".ctor()")]
class Unused {
[Kept]
[KeptBackingField]
diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs b/test/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs
index 6f21e7b55..8d3bb6372 100644
--- a/test/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs
+++ b/test/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs
@@ -4,9 +4,11 @@ namespace Mono.Linker.Tests.Cases.LinkXml {
class UnusedPropertyPreservedByLinkXmlIsKept {
public static void Main ()
{
+ new Unused (); // Used to avoid lazy body marking
}
[Kept]
+ [KeptMember (".ctor()")]
class Unused {
[Kept]
[KeptBackingField]
diff --git a/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj b/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
index 0c23e777b..72e832415 100644
--- a/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
+++ b/test/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
@@ -179,6 +179,7 @@
<Compile Include="Basic\UsedEventOnInterfaceIsRemovedWhenUsedFromClass.cs" />
<Compile Include="Basic\UsedPropertyIsKept.cs" />
<Compile Include="Basic\UsedStructIsKept.cs" />
+ <Compile Include="BCLFeatures\ETW\BaseRemovedEventSourceEmptyBody.cs" />
<Compile Include="BCLFeatures\ETW\LocalsOfModifiedMethodAreRemoved.cs" />
<Compile Include="BCLFeatures\ETW\StubbedMethodWithExceptionHandlers.cs" />
<Compile Include="CommandLine\ResponseFilesWork.cs" />
@@ -187,6 +188,7 @@
<Compile Include="CoreLink\InstantiatedStructWithOverridesFromObject.cs" />
<Compile Include="CoreLink\NeverInstantiatedTypeWithOverridesFromObject.cs" />
<Compile Include="CoreLink\NoSecurityPlusOnlyKeepUsedRemovesAllSecurityAttributesFromCoreLibraries.cs" />
+ <Compile Include="Inheritance.AbstractClasses\NoKeptCtor\OverrideRemoval\OverrideOfAbstractIsKeptNonEmpty.cs" />
<Compile Include="CoreLink\InstantiatedTypeWithOverridesFromObject.cs" />
<Compile Include="Inheritance.AbstractClasses\NoKeptCtor\OverrideRemoval\CanDisableOverrideRemoval.cs" />
<Compile Include="Inheritance.AbstractClasses\NoKeptCtor\OverrideRemoval\OverrideOfAbstractIsKept.cs" />
@@ -354,6 +356,37 @@
<Compile Include="Inheritance.VirtualMethods\UsedTypeWithOverrideOfVirtualMethodHasOverrideKept.cs" />
<Compile Include="Inheritance.VirtualMethods\VirtualMethodGetsPerservedIfBaseMethodGetsInvoked.cs" />
<Compile Include="Inheritance.VirtualMethods\VirtualMethodGetsStrippedIfImplementingMethodGetsInvokedDirectly.cs" />
+ <Compile Include="UnreachableBody\CanDisableLazyBodyMarking.cs" />
+ <Compile Include="UnreachableBody\Dependencies\OtherAssembly.cs" />
+ <Compile Include="UnreachableBody\DoesNotApplyToCopiedAssembly.cs" />
+ <Compile Include="UnreachableBody\DoesNotApplyToCopiedAssembly2.cs" />
+ <Compile Include="UnreachableBody\DoesNotApplyToSavedAssembly.cs" />
+ <Compile Include="UnreachableBody\DoesNotApplyToSavedAssembly2.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingEmpty.cs" />
+ <Compile Include="UnreachableBody\ExplicitInstructionCheck.cs" />
+ <Compile Include="UnreachableBody\InterfaceMethod.cs" />
+ <Compile Include="UnreachableBody\MixOfMethods.cs" />
+ <Compile Include="UnreachableBody\LinkedOtherIncludedLibrary.cs" />
+ <Compile Include="UnreachableBody\LinkedOtherIncludedLibraryNoInstanceCtor.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingReturnDouble.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingReturnFalse.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingReturnFloat.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingReturnInt.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingReturnLong.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingReturnNull.cs" />
+ <Compile Include="UnreachableBody\NotWorthConvertingReturnTrue.cs" />
+ <Compile Include="UnreachableBody\OverrideOfAbstractAndInterfaceMethodCalledFromLocal.cs" />
+ <Compile Include="UnreachableBody\OverrideOfAbstractAndInterfaceMethodCalledFromLocal2.cs" />
+ <Compile Include="UnreachableBody\OverrideOfAbstractAndInterfaceMethodCalledFromLocal3.cs" />
+ <Compile Include="UnreachableBody\OverrideOfAbstractAndInterfaceMethodWhenInterfaceRemoved2.cs" />
+ <Compile Include="UnreachableBody\OverrideOfAbstractIsStubbed.cs" />
+ <Compile Include="UnreachableBody\OverrideOfAbstractIsStubbedWithUnusedInterface.cs" />
+ <Compile Include="UnreachableBody\SimpleGetter.cs" />
+ <Compile Include="UnreachableBody\SimpleMethod.cs" />
+ <Compile Include="UnreachableBody\OverrideOfAVirtual.cs" />
+ <Compile Include="UnreachableBody\SimpleSetter.cs" />
+ <Compile Include="UnreachableBody\WorksWithLinkXml.cs" />
+ <Compile Include="UnreachableBody\WorksWithPreserveDependency.cs" />
<Compile Include="Libraries\CanLinkPublicApisOfLibrary.cs" />
<Compile Include="Libraries\DefaultLibraryLinkBehavior.cs" />
<Compile Include="Libraries\Dependencies\UserAssemblyActionWorks_Lib.cs" />
@@ -614,6 +647,8 @@
<Content Include="Inheritance.Interfaces\OnReferenceType\UnusedInterfaceHasMethodPreservedViaXml.xml" />
<Content Include="Inheritance.Interfaces\OnValueType\UnusedExplicitInterfaceHasMethodPreservedViaXml.xml" />
<Content Include="Inheritance.Interfaces\OnValueType\UnusedInterfaceHasMethodPreservedViaXml.xml" />
+ <Content Include="UnreachableBody\Dependencies\OtherAssemblyNoInstanceCtor.il" />
+ <Content Include="UnreachableBody\WorksWithLinkXml.xml" />
<Content Include="LinkXml\AssemblyWithPreserveAll.xml" />
<Content Include="LinkXml\CanPreserveTypesUsingRegex.xml" />
<Content Include="LinkXml\CanPreserveAnExportedType.xml" />
diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs
index fc634f0a6..fa48bc8e4 100644
--- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs
+++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs
@@ -5,12 +5,15 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies {
class PreserveDependencyMethod {
public static void Main ()
{
+ new B (); // Needed to avoid lazy body marking stubbing
+
B.Method ();
B.SameContext ();
B.Broken ();
B.Conditional ();
}
+ [KeptMember (".ctor()")]
class B
{
[Kept]
@@ -25,6 +28,7 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies {
[Kept]
[PreserveDependency ("Dependency1()", "Mono.Linker.Tests.Cases.PreserveDependencies.C")]
[PreserveDependency ("Dependency2`1 ( T[] , System.Int32 ) ", "Mono.Linker.Tests.Cases.PreserveDependencies.C")]
+ [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.C")] // To avoid lazy body marking stubbing
[PreserveDependency ("field", "Mono.Linker.Tests.Cases.PreserveDependencies.C")]
[PreserveDependency ("NextOne (Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested&)", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested")]
[PreserveDependency ("Property", "Mono.Linker.Tests.Cases.PreserveDependencies.C")]
@@ -64,6 +68,7 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies {
}
}
+ [KeptMember (".ctor()")]
class C
{
[Kept]
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs
index 774a46489..49e1dc5a6 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs
@@ -5,14 +5,18 @@ namespace Mono.Linker.Tests.Cases.Reflection {
public class EventUsedViaReflection {
public static void Main ()
{
- var eventInfo = typeof (EventUsedViaReflection).GetEvent ("Event");
+ new Foo (); // Needed to avoid lazy body marking stubbing
+ var eventInfo = typeof (Foo).GetEvent ("Event");
eventInfo.GetAddMethod (false);
}
- [Kept]
- [KeptBackingField]
- [KeptEventAddMethod]
- [KeptEventRemoveMethod]
- event EventHandler<EventArgs> Event;
+ [KeptMember (".ctor()")]
+ class Foo {
+ [Kept]
+ [KeptBackingField]
+ [KeptEventAddMethod]
+ [KeptEventRemoveMethod]
+ event EventHandler<EventArgs> Event;
+ }
}
}
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflectionWithDefaultBindingFlags.cs b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflectionWithDefaultBindingFlags.cs
index 7a2a4ae10..b27623ac6 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflectionWithDefaultBindingFlags.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflectionWithDefaultBindingFlags.cs
@@ -5,32 +5,36 @@ namespace Mono.Linker.Tests.Cases.Reflection {
public class MethodUsedViaReflectionWithDefaultBindingFlags {
public static void Main ()
{
- var method = typeof (MethodUsedViaReflectionWithDefaultBindingFlags).GetMethod ("OnlyCalledViaReflection");
+ new Foo (); // Needed to avoid lazy body marking stubbing
+ var method = typeof (Foo).GetMethod ("OnlyCalledViaReflection");
method.Invoke (null, new object[] { });
}
- [Kept]
- private static int OnlyCalledViaReflection ()
- {
- return 42;
- }
+ [KeptMember (".ctor()")]
+ class Foo {
+ [Kept]
+ private static int OnlyCalledViaReflection ()
+ {
+ return 42;
+ }
- [Kept]
- private int OnlyCalledViaReflection (int foo)
- {
- return 43;
- }
+ [Kept]
+ private int OnlyCalledViaReflection (int foo)
+ {
+ return 43;
+ }
- [Kept]
- public int OnlyCalledViaReflection (int foo, int bar)
- {
- return 44;
- }
+ [Kept]
+ public int OnlyCalledViaReflection (int foo, int bar)
+ {
+ return 44;
+ }
- [Kept]
- public static int OnlyCalledViaReflection (int foo, int bar, int baz)
- {
- return 45;
+ [Kept]
+ public static int OnlyCalledViaReflection (int foo, int bar, int baz)
+ {
+ return 45;
+ }
}
}
}
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/MightKeepExtraThings.cs b/test/Mono.Linker.Tests.Cases/Reflection/MightKeepExtraThings.cs
index b5b6a1c52..091885e28 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/MightKeepExtraThings.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/MightKeepExtraThings.cs
@@ -6,6 +6,8 @@ namespace Mono.Linker.Tests.Cases.Reflection {
public class MightKeepExtraThings {
public static void Main ()
{
+ new A (); // Needed to avoid lazy body marking stubbing
+ new B (); // Needed to avoid lazy body marking stubbing
var typeA = typeof (A);
var typeB = typeof (B);
Console.WriteLine (typeB); // Use typeB so the C# compiler keeps it in the IL code.
@@ -14,6 +16,7 @@ namespace Mono.Linker.Tests.Cases.Reflection {
}
[Kept]
+ [KeptMember (".ctor()")]
public class A {
[Kept]
public int Foo ()
@@ -23,6 +26,7 @@ namespace Mono.Linker.Tests.Cases.Reflection {
}
[Kept]
+ [KeptMember (".ctor()")]
public class B {
[Kept]
public int Foo ()
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/CanDisableLazyBodyMarking.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/CanDisableLazyBodyMarking.cs
new file mode 100644
index 000000000..4f72c7798
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/CanDisableLazyBodyMarking.cs
@@ -0,0 +1,32 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupLinkerArgument ("--disable-opt", "unreachablebodies")]
+ public class CanDisableLazyBodyMarking {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public void Method ()
+ {
+ UsedByMethod ();
+ }
+
+ [Kept]
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssembly.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssembly.cs
new file mode 100644
index 000000000..8e7abcd65
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssembly.cs
@@ -0,0 +1,18 @@
+namespace Mono.Linker.Tests.Cases.UnreachableBody.Dependencies {
+ public class OtherAssembly {
+ public static void UnusedSanityCheck ()
+ {
+ }
+
+ public class Foo {
+ public void Method ()
+ {
+ UsedByMethod ();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssemblyNoInstanceCtor.il b/test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssemblyNoInstanceCtor.il
new file mode 100644
index 000000000..fdf7516aa
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/Dependencies/OtherAssemblyNoInstanceCtor.il
@@ -0,0 +1,63 @@
+
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.1
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+}
+.assembly other
+{
+ .hash algorithm 0x00008004
+ .ver 0:0:0:0
+}
+.module other.dll
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public auto ansi beforefieldinit Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor
+ extends [mscorlib]System.Object
+{
+ .class auto ansi nested public beforefieldinit Foo
+ extends [mscorlib]System.Object
+ {
+ .method public hidebysig instance void
+ Method() cil managed
+ {
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor/Foo::UsedByMethod()
+ IL_0006: ret
+ } // end of method Foo::Method
+
+ .method private hidebysig instance void
+ UsedByMethod() cil managed
+ {
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method Foo::UsedByMethod
+
+ } // end of class Foo
+
+ .method public hidebysig static void UnusedSanityCheck() cil managed
+ {
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ }
+
+ .method public hidebysig specialname rtspecialname
+ instance void .ctor() cil managed
+ {
+ // Code size 7 (0x7)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance void [mscorlib]System.Object::.ctor()
+ IL_0006: ret
+ }
+
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly.cs
new file mode 100644
index 000000000..49d2f6445
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly.cs
@@ -0,0 +1,23 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+using Mono.Linker.Tests.Cases.UnreachableBody.Dependencies;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupLinkerAction ("copy", "other")]
+ [SetupCompileBefore ("other.dll", new [] {typeof (OtherAssembly)})]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly.Foo), "Method()")]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly.Foo), "UsedByMethod()")]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly), "UnusedSanityCheck()")]
+ public class DoesNotApplyToCopiedAssembly {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (OtherAssembly.Foo f)
+ {
+ f.Method ();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly2.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly2.cs
new file mode 100644
index 000000000..27189d299
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToCopiedAssembly2.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [Define ("OTHER_INCLUDED")]
+ [SetupLinkerAction ("copy", "other")]
+ [SetupCompileBefore ("other.dll", new [] { "Dependencies/OtherAssemblyNoInstanceCtor.il" })]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor/Foo", "Method()")]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor/Foo", "UsedByMethod()")]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor", "UnusedSanityCheck()")]
+ public class DoesNotApplyToCopiedAssembly2 {
+ public static void Main ()
+ {
+#if OTHER_INCLUDED
+ UsedToMarkMethod (null);
+#endif
+ }
+
+#if OTHER_INCLUDED
+ [Kept]
+ static void UsedToMarkMethod (Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor.Foo f)
+ {
+ f.Method ();
+ }
+#endif
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly.cs
new file mode 100644
index 000000000..5c15f34eb
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly.cs
@@ -0,0 +1,23 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+using Mono.Linker.Tests.Cases.UnreachableBody.Dependencies;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupLinkerAction ("save", "other")]
+ [SetupCompileBefore ("other.dll", new [] {typeof (OtherAssembly)})]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly.Foo), "Method()")]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly.Foo), "UsedByMethod()")]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly), "UnusedSanityCheck()")]
+ public class DoesNotApplyToSavedAssembly {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (OtherAssembly.Foo f)
+ {
+ f.Method ();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly2.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly2.cs
new file mode 100644
index 000000000..6e8fd17fb
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/DoesNotApplyToSavedAssembly2.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [Define ("OTHER_INCLUDED")]
+ [SetupLinkerAction ("save", "other")]
+ [SetupCompileBefore ("other.dll", new [] { "Dependencies/OtherAssemblyNoInstanceCtor.il" })]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor/Foo", "Method()")]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor/Foo", "UsedByMethod()")]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor", "UnusedSanityCheck()")]
+ public class DoesNotApplyToSavedAssembly2 {
+ public static void Main ()
+ {
+#if OTHER_INCLUDED
+ UsedToMarkMethod (null);
+#endif
+ }
+
+#if OTHER_INCLUDED
+ [Kept]
+ static void UsedToMarkMethod (Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor.Foo f)
+ {
+ f.Method ();
+ }
+#endif
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/ExplicitInstructionCheck.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/ExplicitInstructionCheck.cs
new file mode 100644
index 000000000..743496e60
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/ExplicitInstructionCheck.cs
@@ -0,0 +1,35 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class ExplicitInstructionCheck {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ [ExpectedInstructionSequence(new []
+ {
+ "ldstr",
+ "newobj",
+ "throw"
+ })]
+ public void Method ()
+ {
+ UsedByMethod ();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/InterfaceMethod.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/InterfaceMethod.cs
new file mode 100644
index 000000000..e28737ad1
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/InterfaceMethod.cs
@@ -0,0 +1,38 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class InterfaceMethod {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ IFoo i = f;
+ i.Method ();
+ }
+
+ [Kept]
+ interface IFoo {
+ [Kept]
+ void Method ();
+ }
+
+ [Kept]
+ [KeptInterface (typeof (IFoo))]
+ class Foo : IFoo {
+ [Kept]
+ [ExpectBodyModified]
+ public void Method ()
+ {
+ UsedByMethod ();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibrary.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibrary.cs
new file mode 100644
index 000000000..0868122e7
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibrary.cs
@@ -0,0 +1,23 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+using Mono.Linker.Tests.Cases.UnreachableBody.Dependencies;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupLinkerArgument ("-r", "other")]
+ [SetupCompileBefore ("other.dll", new [] {typeof (OtherAssembly)})]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly.Foo), "Method()")]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly.Foo), "UsedByMethod()")]
+ [KeptMemberInAssembly ("other.dll", typeof (OtherAssembly), "UnusedSanityCheck()")]
+ public class LinkedOtherIncludedLibrary {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (OtherAssembly.Foo f)
+ {
+ f.Method ();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibraryNoInstanceCtor.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibraryNoInstanceCtor.cs
new file mode 100644
index 000000000..1d4e368fb
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/LinkedOtherIncludedLibraryNoInstanceCtor.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [Define ("OTHER_INCLUDED")]
+ [SetupLinkerArgument ("-r", "other")]
+ [SetupCompileBefore ("other.dll", new [] { "Dependencies/OtherAssemblyNoInstanceCtor.il" })]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor/Foo", "Method()")]
+ [RemovedMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor/Foo", "UsedByMethod()")]
+ [KeptMemberInAssembly ("other.dll", "Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor", "UnusedSanityCheck()")]
+ public class LinkedOtherIncludedLibraryNoInstanceCtor {
+ public static void Main ()
+ {
+#if OTHER_INCLUDED
+ UsedToMarkMethod (null);
+#endif
+ }
+
+#if OTHER_INCLUDED
+ [Kept]
+ static void UsedToMarkMethod (Mono.Linker.Tests.Cases.UnreachableBody.Dependencies.OtherAssemblyNoInstanceCtor.Foo f)
+ {
+ f.Method ();
+ }
+#endif
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/MixOfMethods.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/MixOfMethods.cs
new file mode 100644
index 000000000..17047ad7d
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/MixOfMethods.cs
@@ -0,0 +1,148 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class MixOfMethods {
+ public static void Main ()
+ {
+ UseInstanceMethods (null);
+ Foo.PublicStatic ();
+ Base2.Base2PublicStatic ();
+ Base.BasePublicStatic ();
+ }
+
+ [Kept]
+ static void UseInstanceMethods (Foo f)
+ {
+ f.Method1 ();
+ f.Method2 ();
+ f.Method3 ();
+
+ f.BaseMethod1 ();
+ f.BaseMethod2 ();
+ f.BaseMethod3 ();
+
+ f.Base2Method1 ();
+ f.Base2Method2 ();
+ f.Base2Method3 ();
+ }
+
+ [Kept]
+ class Base {
+ [Kept]
+ [ExpectBodyModified]
+ public void BaseMethod1 ()
+ {
+ UsedByInstance ();
+ }
+
+ [Kept]
+ [ExpectBodyModified]
+ public void BaseMethod2 ()
+ {
+ UsedByInstance ();
+ }
+
+ [Kept]
+ [ExpectBodyModified]
+ public void BaseMethod3 ()
+ {
+ UsedByInstance ();
+ }
+
+ void UsedByInstance ()
+ {
+ }
+
+ [Kept]
+ public static void BasePublicStatic ()
+ {
+ UsedByStatic();
+ }
+
+ [Kept]
+ static void UsedByStatic ()
+ {
+ }
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ class Base2 : Base {
+ [Kept]
+ [ExpectBodyModified]
+ public void Base2Method1 ()
+ {
+ UsedByInstance ();
+ }
+
+ [Kept]
+ [ExpectBodyModified]
+ public void Base2Method2 ()
+ {
+ UsedByInstance ();
+ }
+
+ [Kept]
+ [ExpectBodyModified]
+ public void Base2Method3 ()
+ {
+ UsedByInstance ();
+ }
+
+ void UsedByInstance ()
+ {
+ }
+
+ [Kept]
+ public static void Base2PublicStatic ()
+ {
+ UsedByStatic();
+ }
+
+ [Kept]
+ static void UsedByStatic ()
+ {
+ }
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base2))]
+ class Foo : Base2 {
+ [Kept]
+ [ExpectBodyModified]
+ public void Method1 ()
+ {
+ UsedByInstance ();
+ }
+
+ [Kept]
+ [ExpectBodyModified]
+ public void Method2 ()
+ {
+ UsedByInstance ();
+ }
+
+ [Kept]
+ [ExpectBodyModified]
+ public void Method3 ()
+ {
+ UsedByInstance ();
+ }
+
+ void UsedByInstance ()
+ {
+ }
+
+ [Kept]
+ public static void PublicStatic ()
+ {
+ UsedByStatic();
+ }
+
+ [Kept]
+ static void UsedByStatic ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingEmpty.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingEmpty.cs
new file mode 100644
index 000000000..8f60a53f8
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingEmpty.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ /// <summary>
+ /// Stubbing an empty method would result in more instructions. It's more size efficient to just leave it alone
+ /// </summary>
+ public class NotWorthConvertingEmpty {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnDouble.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnDouble.cs
new file mode 100644
index 000000000..e4399f9cb
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnDouble.cs
@@ -0,0 +1,28 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupCompileArgument ("/optimize+")]
+ public class NotWorthConvertingReturnDouble {
+ public static void Main ()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo
+ {
+ [Kept]
+ public double Method ()
+ {
+ return 0.0;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFalse.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFalse.cs
new file mode 100644
index 000000000..03c80231e
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFalse.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupCompileArgument ("/optimize+")]
+ public class NotWorthConvertingReturnFalse {
+ public static void Main ()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public bool Method ()
+ {
+ return false;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFloat.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFloat.cs
new file mode 100644
index 000000000..eac4d70f1
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnFloat.cs
@@ -0,0 +1,28 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupCompileArgument ("/optimize+")]
+ public class NotWorthConvertingReturnFloat {
+ public static void Main ()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo
+ {
+ [Kept]
+ public float Method ()
+ {
+ return 1.0f;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnInt.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnInt.cs
new file mode 100644
index 000000000..678df5e80
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnInt.cs
@@ -0,0 +1,90 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupCompileArgument ("/optimize+")]
+ public class NotWorthConvertingReturnInt {
+ public static void Main ()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ f.Method1 ();
+ f.Method2 ();
+ f.Method3 ();
+ f.Method4 ();
+ f.Method5 ();
+ f.Method6 ();
+ f.Method7 ();
+ f.Method8 ();
+ f.Method9 ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public int Method ()
+ {
+ return 0;
+ }
+
+ [Kept]
+ public int Method1 ()
+ {
+ return 1;
+ }
+
+ [Kept]
+ public int Method2 ()
+ {
+ return 2;
+ }
+
+ [Kept]
+ public int Method3 ()
+ {
+ return 3;
+ }
+
+ [Kept]
+ public int Method4 ()
+ {
+ return 4;
+ }
+
+ [Kept]
+ public int Method5 ()
+ {
+ return 5;
+ }
+
+ [Kept]
+ public int Method6 ()
+ {
+ return 6;
+ }
+
+ [Kept]
+ public int Method7 ()
+ {
+ return 7;
+ }
+
+ [Kept]
+ public int Method8 ()
+ {
+ return 8;
+ }
+
+ [Kept]
+ public int Method9 ()
+ {
+ return 9;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnLong.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnLong.cs
new file mode 100644
index 000000000..3d21cac45
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnLong.cs
@@ -0,0 +1,28 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupCompileArgument ("/optimize+")]
+ public class NotWorthConvertingReturnLong {
+ public static void Main ()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo
+ {
+ [Kept]
+ public long Method ()
+ {
+ return 9223372036854775807;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnNull.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnNull.cs
new file mode 100644
index 000000000..13d3234a9
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnNull.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupCompileArgument ("/optimize+")]
+ public class NotWorthConvertingReturnNull {
+ public static void Main ()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public object Method ()
+ {
+ return null;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnTrue.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnTrue.cs
new file mode 100644
index 000000000..87b11b5dc
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/NotWorthConvertingReturnTrue.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ [SetupCompileArgument ("/optimize+")]
+ public class NotWorthConvertingReturnTrue {
+ public static void Main ()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public bool Method ()
+ {
+ return true;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAVirtual.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAVirtual.cs
new file mode 100644
index 000000000..696904219
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAVirtual.cs
@@ -0,0 +1,44 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class OverrideOfAVirtual {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Base {
+ [Kept]
+ [ExpectBodyModified]
+ public virtual void Method ()
+ {
+ UsedByMethod();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ class Foo : Base {
+ // A callvirt to Base.Method() appears in the IL so this override can be removed entirely
+ public override void Method ()
+ {
+ UsedByMethod ();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal.cs
new file mode 100644
index 000000000..c3785889f
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal.cs
@@ -0,0 +1,46 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class OverrideOfAbstractAndInterfaceMethodCalledFromLocal {
+ public static void Main ()
+ {
+ Foo b = HelperToMarkFooAndRequireBase ();
+ IBar i = b;
+ i.Method ();
+ }
+
+ [Kept]
+ static Foo HelperToMarkFooAndRequireBase ()
+ {
+ return null;
+ }
+
+ [Kept]
+ abstract class Base {
+ [Kept] // FIXME : Technically this can be removed
+ public abstract void Method ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ [KeptInterface (typeof (IBar))]
+ class Foo : Base, IBar {
+ [Kept]
+ [ExpectBodyModified]
+ public override void Method ()
+ {
+ UsedByOverride ();
+ }
+
+ void UsedByOverride ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IBar {
+ [Kept]
+ void Method ();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal2.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal2.cs
new file mode 100644
index 000000000..338efabfa
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal2.cs
@@ -0,0 +1,53 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class OverrideOfAbstractAndInterfaceMethodCalledFromLocal2 {
+ public static void Main ()
+ {
+ Foo f = HelperToMarkFooAndRequireBase ();
+ f.Method ();
+ IBar i = GetAnIBar ();
+ i.Method ();
+ }
+
+ [Kept]
+ static Foo HelperToMarkFooAndRequireBase ()
+ {
+ return null;
+ }
+
+ [Kept]
+ static IBar GetAnIBar ()
+ {
+ return null;
+ }
+
+ [Kept]
+ abstract class Base {
+ [Kept] // FIXME : Technically this can be removed
+ public abstract void Method ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ [KeptInterface (typeof (IBar))]
+ class Foo : Base, IBar {
+ [Kept]
+ [ExpectBodyModified]
+ public override void Method ()
+ {
+ UsedByOverride ();
+ }
+
+ void UsedByOverride ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IBar {
+ [Kept]
+ void Method();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal3.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal3.cs
new file mode 100644
index 000000000..f85059918
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodCalledFromLocal3.cs
@@ -0,0 +1,40 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class OverrideOfAbstractAndInterfaceMethodCalledFromLocal3 {
+ public static void Main ()
+ {
+ Foo b = null;
+ IBar i = b;
+ i.Method ();
+ }
+
+ [Kept]
+ abstract class Base {
+ [Kept] // FIXME : Technically this can be removed
+ public abstract void Method ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ [KeptInterface (typeof (IBar))]
+ class Foo : Base, IBar {
+ [Kept]
+ [ExpectBodyModified]
+ public override void Method ()
+ {
+ UsedByOverride ();
+ }
+
+ void UsedByOverride ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IBar {
+ [Kept]
+ void Method ();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodWhenInterfaceRemoved2.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodWhenInterfaceRemoved2.cs
new file mode 100644
index 000000000..4a2832402
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractAndInterfaceMethodWhenInterfaceRemoved2.cs
@@ -0,0 +1,58 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class OverrideOfAbstractAndInterfaceMethodWhenInterfaceRemoved2 {
+ public static void Main ()
+ {
+ Foo f = HelperToMarkFooAndRequireBase ();
+ f.Method ();
+ // Use IBar in another method so that IBar can be removed from Foo
+ HelperToMarkIBar ();
+ }
+
+ [Kept]
+ static Foo HelperToMarkFooAndRequireBase ()
+ {
+ return null;
+ }
+
+ [Kept]
+ static IBar GetAnIBar ()
+ {
+ return null;
+ }
+
+ [Kept]
+ static void HelperToMarkIBar()
+ {
+ GetAnIBar().Method();
+ }
+
+ [Kept]
+ abstract class Base {
+ [Kept]
+ public abstract void Method ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ class Foo : Base, IBar {
+ [Kept]
+ [ExpectBodyModified]
+ public override void Method ()
+ {
+ UsedByOverride ();
+ }
+
+ void UsedByOverride ()
+ {
+ }
+ }
+
+ [Kept]
+ interface IBar {
+ [Kept]
+ void Method();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbed.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbed.cs
new file mode 100644
index 000000000..3301b4b6a
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbed.cs
@@ -0,0 +1,39 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class OverrideOfAbstractIsStubbed {
+ public static void Main ()
+ {
+ Base b = HelperToMarkFooAndRequireBase ();
+ b.Method ();
+ }
+
+ [Kept]
+ static Foo HelperToMarkFooAndRequireBase ()
+ {
+ return null;
+ }
+
+ [Kept]
+ abstract class Base
+ {
+ [Kept]
+ public abstract void Method ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ class Foo : Base {
+ [Kept]
+ [ExpectBodyModified]
+ public override void Method ()
+ {
+ UsedByOverride ();
+ }
+
+ void UsedByOverride ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbedWithUnusedInterface.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbedWithUnusedInterface.cs
new file mode 100644
index 000000000..11087de08
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/OverrideOfAbstractIsStubbedWithUnusedInterface.cs
@@ -0,0 +1,44 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class OverrideOfAbstractIsStubbedWithUnusedInterface {
+ public static void Main ()
+ {
+ Base b = HelperToMarkFooAndRequireBase ();
+ b.Method ();
+ }
+
+ [Kept]
+ static Foo HelperToMarkFooAndRequireBase ()
+ {
+ return null;
+ }
+
+ [Kept]
+ abstract class Base
+ {
+ [Kept]
+ public abstract void Method ();
+ }
+
+ [Kept]
+ [KeptBaseType (typeof (Base))]
+ class Foo : Base, IBar {
+ [Kept]
+ [ExpectBodyModified]
+ public override void Method ()
+ {
+ UsedByOverride ();
+ }
+
+ void UsedByOverride ()
+ {
+ }
+ }
+
+ interface IBar
+ {
+ void Method();
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleGetter.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleGetter.cs
new file mode 100644
index 000000000..1c93c6a8f
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleGetter.cs
@@ -0,0 +1,22 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class SimpleGetter {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ var tmp = f.Property;
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public string Property { [Kept] [ExpectBodyModified] get; set; }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleMethod.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleMethod.cs
new file mode 100644
index 000000000..f69f1f5ab
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleMethod.cs
@@ -0,0 +1,30 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class SimpleMethod {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Method ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ [ExpectBodyModified]
+ public void Method ()
+ {
+ UsedByMethod ();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleSetter.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleSetter.cs
new file mode 100644
index 000000000..54c22d65c
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/SimpleSetter.cs
@@ -0,0 +1,22 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class SimpleSetter {
+ public static void Main()
+ {
+ UsedToMarkMethod (null);
+ }
+
+ [Kept]
+ static void UsedToMarkMethod (Foo f)
+ {
+ f.Property = string.Empty;
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ public string Property { get; [Kept] [ExpectBodyModified] set; }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.cs
new file mode 100644
index 000000000..a366a50b0
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.cs
@@ -0,0 +1,23 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class WorksWithLinkXml {
+ public static void Main()
+ {
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ [ExpectBodyModified]
+ public void InstanceMethod ()
+ {
+ UsedByMethod ();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.xml b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.xml
new file mode 100644
index 000000000..1e89edf42
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithLinkXml.xml
@@ -0,0 +1,7 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.UnreachableBody.WorksWithLinkXml/Foo">
+ <method signature="System.Void InstanceMethod()"/>
+ </type>
+ </assembly>
+</linker>
diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs
new file mode 100644
index 000000000..3a6ed1d27
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs
@@ -0,0 +1,31 @@
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.UnreachableBody {
+ public class WorksWithPreserveDependency {
+ public static void Main()
+ {
+ Foo.StaticMethod ();
+ }
+
+ [Kept]
+ class Foo {
+ [Kept]
+ [PreserveDependency ("InstanceMethod()")]
+ public static void StaticMethod ()
+ {
+ }
+
+ [Kept]
+ [ExpectBodyModified]
+ public void InstanceMethod ()
+ {
+ UsedByMethod ();
+ }
+
+ void UsedByMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
index e5e9085f2..17e380783 100644
--- a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
+++ b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
@@ -125,6 +125,11 @@ namespace Mono.Linker.Tests.TestCases
{
return NUnitCasesBySuiteName ("CommandLine");
}
+
+ public static IEnumerable<TestCaseData> UnreachableBodyTests ()
+ {
+ return NUnitCasesBySuiteName ("UnreachableBody");
+ }
public static TestCaseCollector CreateCollector ()
{
diff --git a/test/Mono.Linker.Tests/TestCases/TestSuites.cs b/test/Mono.Linker.Tests/TestCases/TestSuites.cs
index 994448f68..210442e28 100644
--- a/test/Mono.Linker.Tests/TestCases/TestSuites.cs
+++ b/test/Mono.Linker.Tests/TestCases/TestSuites.cs
@@ -144,6 +144,12 @@ namespace Mono.Linker.Tests.TestCases
Run (testCase);
}
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.UnreachableBodyTests))]
+ public void UnreachableBodyTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
protected virtual void Run (TestCase testCase)
{
var runner = new TestRunner (new ObjectFactory ());