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:
authorSven Boemer <sbomer@gmail.com>2022-06-30 00:15:31 +0300
committerGitHub <noreply@github.com>2022-06-30 00:15:31 +0300
commitbc46e445deb1411cc597019d693ddc5b4e5e24f4 (patch)
tree332512db149b2a81113a8ef277abfa3082eb09c0 /test/Mono.Linker.Tests.Cases/DataFlow
parente10038dcd0bff151e3367644eb3cf391e56ead28 (diff)
Add compiler-generated code dataflow analysis (#2842)
This treats fields of display classes and state machines as hoisted locals. We track all assignments to hoisted locals within a method group (the set of compiler-generated code reachable from a given user method). The analysis is technically flow-insensitive, because it assumes that any assignment to a hoisted local can reach any read of the same local. This will produce extra warnings in some cases, but it prevents holes: - State will "flow" out of nested functions. That is, writes (to hoisted locals) within nested functions will reach reads in the enclosing user method - Lambdas are analyzed at the point of delegate conversion, but with all possible states of captured variables. So effectively, writes after the lambda declaration will reach reads within the lambda. Previously, hoisted locals were treated as unannotated, so they would produce dataflow warnings if they reached an annotated location. Now that we analyze hoisted locals, cases where the value satisfies requirements at the point of consumption won't warn. This means that accessing these fields (representing hoisted locals) via reflection is problematic, since it could mutate the values of these fields and invalidate the correctness analysis. For this reason we now warn on reflection access to compiler-generated fields. To prevent noise, we only warn for reflection access to compiler-generated fields that represent types which may be annotated - so Type, string, etc. - but not int. This is technically a hole because ints also participate in dataflow analysis but we are choosing this tradeoff to avoid excess warnings for integers. This also includes some cleanup of the type hierarchy logic and extra comments to make it more clear how this interacts with warnings for reflection access to compiler-generated code.
Diffstat (limited to 'test/Mono.Linker.Tests.Cases/DataFlow')
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs83
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs562
2 files changed, 613 insertions, 32 deletions
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs
index 1b5f65c7e..804f2a370 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs
@@ -30,8 +30,6 @@ namespace Mono.Linker.Tests.Cases.DataFlow
class BaseTypeWithIteratorStateMachines
{
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
public static IEnumerable<int> BaseIteratorWithCorrectDataflow ()
{
var t = GetAll ();
@@ -42,6 +40,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[ExpectedWarning ("IL2120", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "MoveNext",
ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2120", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "<t>",
+ ProducedBy = ProducedBy.Trimmer)]
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
class IteratorStateMachines : BaseTypeWithIteratorStateMachines
{
@@ -63,25 +63,33 @@ namespace Mono.Linker.Tests.Cases.DataFlow
}
[ExpectedWarning ("IL2119", "<" + nameof (IteratorWithCorrectDataflow) + ">", "MoveNext", CompilerGeneratedCode = true)]
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
- ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2119", "<t_IteratorWithCorrectDataflow>", CompilerGeneratedCode = true)]
public static IEnumerable<int> IteratorWithCorrectDataflow ()
{
- var t = GetAll ();
+ var t_IteratorWithCorrectDataflow = GetAll ();
yield return 0;
- t.RequiresAll ();
+ t_IteratorWithCorrectDataflow.RequiresAll ();
+ }
+
+ [ExpectedWarning ("IL2119", "<" + nameof (IteratorWithIntegerDataflow) + ">", "MoveNext", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL2119", "<types>", CompilerGeneratedCode = true)]
+ public static IEnumerable<int> IteratorWithIntegerDataflow ()
+ {
+ int integerLocal = 0;
+ yield return 0;
+ var types = new Type[] { GetWithPublicMethods (), GetWithPublicFields () };
+ types[integerLocal].RequiresPublicMethods ();
}
[ExpectedWarning ("IL2119", "<" + nameof (IteratorWithProblematicDataflow) + ">", "MoveNext", CompilerGeneratedCode = true)]
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
+ [ExpectedWarning ("IL2119", "<t_IteratorWithProblematicDataflow>", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
ProducedBy = ProducedBy.Trimmer)]
public static IEnumerable<int> IteratorWithProblematicDataflow ()
{
- var t = GetWithPublicMethods ();
+ var t_IteratorWithProblematicDataflow = GetWithPublicMethods ();
yield return 0;
- t.RequiresAll ();
+ t_IteratorWithProblematicDataflow.RequiresAll ();
}
[ExpectedWarning ("IL2112", nameof (RUCTypeWithIterators) + "()", "--RUCTypeWithIterators--", CompilerGeneratedCode = true)]
@@ -121,6 +129,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
ProducedBy = ProducedBy.Trimmer)]
[ExpectedWarning ("IL2118", "<" + nameof (IteratorWithCorrectDataflow) + ">", "MoveNext",
ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithIntegerDataflow) + ">", "MoveNext",
+ ProducedBy = ProducedBy.Trimmer)]
[ExpectedWarning ("IL2118", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "MoveNext",
ProducedBy = ProducedBy.Trimmer)]
[ExpectedWarning ("IL2026", nameof (RUCTypeWithIterators) + "()", "--RUCTypeWithIterators--")]
@@ -134,6 +144,18 @@ namespace Mono.Linker.Tests.Cases.DataFlow
// With that, the IL2118 warning should also go away.
[ExpectedWarning ("IL2118", "<" + nameof (RUCTypeWithIterators.InstanceIteratorCallsMethodWithRequires) + ">", "MoveNext",
ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithCorrectDataflow) + ">", "<t_IteratorWithCorrectDataflow>",
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithProblematicDataflow) + ">", "<t_IteratorWithProblematicDataflow>",
+ ProducedBy = ProducedBy.Trimmer)]
+ // Technically the access to IteratorWithIntegerDataflow should warn about access to the integer
+ // field integerLocal, but our heuristics only warn if the field type satisfies the
+ // "IsTypeInterestingForDatafllow" check. This is likely good enough because in most cases the
+ // compiler-generated code will have other hoisted fields with types that _are_ interesting for dataflow.
+ [ExpectedWarning ("IL2118", "<" + nameof (IteratorWithIntegerDataflow) + ">", "<types>",
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (BaseIteratorWithCorrectDataflow) + ">", "<t>",
+ ProducedBy = ProducedBy.Trimmer)]
public static void Test (IteratorStateMachines test = null)
{
typeof (IteratorStateMachines).RequiresAll ();
@@ -156,22 +178,18 @@ namespace Mono.Linker.Tests.Cases.DataFlow
MethodWithRequires ();
}
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
- ProducedBy = ProducedBy.Trimmer)]
public static async Task AsyncWithCorrectDataflow ()
{
- var t = GetAll ();
- t.RequiresAll ();
+ var t_AsyncWithCorrectDataflow = GetAll ();
+ t_AsyncWithCorrectDataflow.RequiresAll ();
}
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
ProducedBy = ProducedBy.Trimmer)]
public static async Task AsyncWithProblematicDataflow ()
{
- var t = GetWithPublicMethods ();
- t.RequiresAll ();
+ var t_AsyncWithProblematicDataflow = GetWithPublicMethods ();
+ t_AsyncWithProblematicDataflow.RequiresAll ();
}
[ExpectedWarning ("IL2118", "<" + nameof (AsyncWithProblematicDataflow) + ">", "MoveNext",
@@ -180,6 +198,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow
ProducedBy = ProducedBy.Trimmer)]
[ExpectedWarning ("IL2118", "<" + nameof (AsyncWithCorrectDataflow) + ">", "MoveNext",
ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithCorrectDataflow) + ">", "<t_AsyncWithCorrectDataflow>",
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (AsyncWithProblematicDataflow) + ">", "<t_AsyncWithProblematicDataflow>",
+ ProducedBy = ProducedBy.Trimmer)]
public static void Test ()
{
typeof (AsyncStateMachines).RequiresAll ();
@@ -202,9 +224,6 @@ namespace Mono.Linker.Tests.Cases.DataFlow
MethodWithRequires ();
}
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
- ProducedBy = ProducedBy.Trimmer)]
public static async IAsyncEnumerable<int> AsyncIteratorWithCorrectDataflow ()
{
var t = GetAll ();
@@ -212,9 +231,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
t.RequiresAll ();
}
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll),
- nameof (AsyncIteratorWithProblematicDataflow), CompilerGeneratedCode = true,
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
ProducedBy = ProducedBy.Trimmer)]
public static async IAsyncEnumerable<int> AsyncIteratorWithProblematicDataflow ()
{
@@ -229,6 +246,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow
ProducedBy = ProducedBy.Trimmer)]
[ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithCorrectDataflow) + ">", "MoveNext",
ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithCorrectDataflow) + ">", "<t>",
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", "<" + nameof (AsyncIteratorWithProblematicDataflow) + ">", "<t>",
+ ProducedBy = ProducedBy.Trimmer)]
public static void Test ()
{
typeof (AsyncIteratorStateMachines).RequiresAll ();
@@ -259,7 +280,6 @@ namespace Mono.Linker.Tests.Cases.DataFlow
static void LambdaWithCorrectDataflow ()
{
var lambda =
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
[ExpectedWarning ("IL2119", "<" + nameof (LambdaWithCorrectDataflow) + ">",
ProducedBy = ProducedBy.Trimmer)]
() => {
@@ -302,8 +322,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
var lambda =
[ExpectedWarning ("IL2119", "<" + nameof (LambdaWithCapturedTypeToDAM) + ">",
ProducedBy = ProducedBy.Trimmer)]
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll),
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
ProducedBy = ProducedBy.Trimmer)]
() => {
t.RequiresAll ();
@@ -424,9 +443,6 @@ namespace Mono.Linker.Tests.Cases.DataFlow
var t = GetAll ();
[ExpectedWarning ("IL2119", "<" + nameof (LocalFunctionWithCapturedTypeToDAM) + ">",
ProducedBy = ProducedBy.Trimmer)]
- // Annotations aren't propagated to hoisted locals: https://github.com/dotnet/linker/issues/2001
- [ExpectedWarning ("IL2077", nameof (DataFlowTypeExtensions.RequiresAll),
- ProducedBy = ProducedBy.Trimmer)]
void LocalFunction ()
{
t.RequiresAll ();
@@ -517,6 +533,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
static Type GetWithPublicMethods () => null;
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)]
+ static Type GetWithPublicFields () => null;
+
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
static Type GetAll () => null;
}
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs
new file mode 100644
index 000000000..f42464e54
--- /dev/null
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs
@@ -0,0 +1,562 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Helpers;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DataFlow
+{
+ [SkipKeptItemsValidation]
+ [SetupCompileArgument ("/unsafe")]
+ [ExpectedNoWarnings]
+ public class CompilerGeneratedCodeDataflow
+ {
+ public static void Main ()
+ {
+ Iterator.Test ();
+ Async.Test ();
+ AsyncIterator.Test ();
+ LocalFunction.Test ();
+ Lambda.Test ();
+ Complex.Test ();
+ }
+
+ class Iterator
+ {
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ CompilerGeneratedCode = true)]
+ static IEnumerable<int> FlowAcrossYieldReturn ()
+ {
+ Type t = GetWithPublicMethods ();
+ yield return 0;
+ t.RequiresAll ();
+ }
+
+ // Linker tracks all assignments of hoisted locals, so this produces warnings.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresPublicFields), CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresPublicMethods), CompilerGeneratedCode = true)]
+ static IEnumerable<int> NoFlowAcrossYieldReturn ()
+ {
+ Type t = GetWithPublicMethods ();
+ t.RequiresPublicMethods ();
+ yield return 0;
+ t = GetWithPublicFields ();
+ t.RequiresPublicFields ();
+ }
+
+ [ExpectedWarning ("IL2067", "publicMethodsType", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
+ static IEnumerable<int> UseParameterBeforeYieldReturn ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type publicMethodsType = null)
+ {
+ publicMethodsType.RequiresAll ();
+ yield return 0;
+ }
+
+ [ExpectedWarning ("IL2067", "unknownType", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
+ static IEnumerable<int> UseUnannotatedParameterBeforeYieldReturn (Type unknownType = null)
+ {
+ unknownType.RequiresAll ();
+ yield return 0;
+ }
+
+ [ExpectedWarning ("IL2067", "publicMethodsType", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
+ static IEnumerable<int> FlowParameterAcrossYieldReturn ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type publicMethodsType = null)
+ {
+ yield return 0;
+ publicMethodsType.RequiresAll ();
+ }
+
+ [ExpectedWarning ("IL2067", "unknownType", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
+ static IEnumerable<int> FlowUnannotatedParameterAcrossYieldReturn (Type unknownType = null)
+ {
+ yield return 0;
+ unknownType.RequiresAll ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
+ // Linker includes backwards branches for hoisted locals, by virtue of tracking all assignments.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
+ static IEnumerable<int> FlowAcrossYieldReturnWithBackwardsBranch (int n = 0)
+ {
+ Type t = GetWithPublicMethods ();
+ for (int i = 0; i < n; i++) {
+ yield return 0;
+ t.RequiresAll ();
+ yield return 1;
+ t = GetWithPublicFields ();
+ }
+ }
+
+ public static void Test ()
+ {
+ FlowAcrossYieldReturn ();
+ NoFlowAcrossYieldReturn ();
+ NoFlowAcrossYieldReturn ();
+ UseParameterBeforeYieldReturn ();
+ UseUnannotatedParameterBeforeYieldReturn ();
+ FlowParameterAcrossYieldReturn ();
+ FlowUnannotatedParameterAcrossYieldReturn ();
+ FlowAcrossYieldReturnWithBackwardsBranch ();
+ }
+ }
+
+ class Async
+ {
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ CompilerGeneratedCode = true)]
+ static async void FlowAcrossAwait ()
+ {
+ Type t = GetWithPublicMethods ();
+ await MethodAsync ();
+ t.RequiresAll ();
+ }
+
+ // Linker tracks all assignments of hoisted locals, so this produces warnings.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresPublicFields), CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresPublicMethods), CompilerGeneratedCode = true)]
+ static async void NoFlowAcrossAwait ()
+ {
+ Type t = GetWithPublicMethods ();
+ t.RequiresPublicMethods ();
+ await MethodAsync ();
+ t = GetWithPublicFields ();
+ t.RequiresPublicFields ();
+ }
+
+ [ExpectedWarning ("IL2067", "publicMethodsType", nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true)]
+ static async void FlowParameterAcrossAwait ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type publicMethodsType = null)
+ {
+ await MethodAsync ();
+ publicMethodsType.RequiresAll ();
+ }
+
+ public static void Test ()
+ {
+ FlowAcrossAwait ();
+ NoFlowAcrossAwait ();
+ FlowParameterAcrossAwait ();
+ }
+ }
+
+ class AsyncIterator
+ {
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
+ ProducedBy = ProducedBy.Trimmer)]
+ static async IAsyncEnumerable<int> FlowAcrossAwaitAndYieldReturn ()
+ {
+ Type t = GetWithPublicMethods ();
+ await MethodAsync ();
+ yield return 0;
+ t.RequiresAll ();
+ }
+
+ public static void Test ()
+ {
+ FlowAcrossAwaitAndYieldReturn ();
+ }
+ }
+
+ class LocalFunction
+ {
+ static void WarningsInBody ()
+ {
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ static void LocalFunction ()
+ {
+ Type t = GetWithPublicMethods ();
+ t.RequiresAll ();
+ }
+
+ LocalFunction ();
+ }
+
+ static void WarningsInBodyUnused ()
+ {
+ // Trimmer doesn't warn because this is unused code.
+ static void LocalFunction ()
+ {
+ Type t = GetWithPublicMethods ();
+ t.RequiresAll ();
+ }
+ }
+
+ static void ReadCapturedVariable ()
+ {
+ Type t = GetWithPublicMethods ();
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction ()
+ {
+ t.RequiresAll ();
+ }
+ }
+
+ static void ReadMergedCapturedVariable (bool b = false)
+ {
+ Type t;
+ if (b) {
+ t = GetWithPublicMethods ();
+ } else {
+ t = GetWithPublicFields ();
+ }
+
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => t.RequiresAll ();
+ }
+
+ static void ReadCapturedVariableInMultipleBranches (bool b = false)
+ {
+ Type t;
+ if (b) {
+ t = GetWithPublicMethods ();
+ LocalFunction ();
+ } else {
+ t = GetWithPublicFields ();
+ LocalFunction ();
+ }
+
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => t.RequiresAll ();
+ }
+
+ static void ReadCapturedVariableInMultipleBranchesDistinct (bool b = false)
+ {
+ Type t;
+ if (b) {
+ t = GetWithPublicMethods ();
+ LocalFunctionRequiresMethods ();
+ } else {
+ t = GetWithPublicFields ();
+ LocalFunctionRequiresFields ();
+ }
+
+ // We include all writes, including ones that can't reach the local function invocation.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresPublicFields),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunctionRequiresFields () => t.RequiresPublicFields ();
+ // We include all writes, including ones that can't reach the local function invocation.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresPublicMethods),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunctionRequiresMethods () => t.RequiresPublicMethods ();
+ }
+
+ static void ReadCapturedVariableWithBackwardsBranch (int i = 0)
+ {
+ Type t = GetWithPublicMethods ();
+ while (true) {
+ LocalFunction ();
+ if (i++ == 5)
+ break;
+ t = GetWithPublicFields ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ // Linker includes backwards branches for hoisted locals, by virtue of tracking all assignments.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => t.RequiresAll ();
+ }
+
+ static void ReadCapturedVariableInMultipleFunctions ()
+ {
+ Type t = GetWithPublicMethods ();
+ LocalFunction ();
+
+ CallerOfLocalFunction ();
+
+ void CallerOfLocalFunction ()
+ {
+ t = GetWithPublicFields ();
+ LocalFunction ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => t.RequiresAll ();
+ }
+
+ static void ReadCapturedVariableInCallGraphCycle ()
+ {
+ Type t = GetUnknownType ();
+ A ();
+
+ void A ()
+ {
+ t = GetWithPublicMethods ();
+ LocalFunction ();
+ B ();
+ }
+
+ void B ()
+ {
+ t = GetWithPublicFields ();
+ LocalFunction ();
+ A ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => t.RequiresAll ();
+ }
+
+ public static void ReadCapturedParameter (Type tParameter)
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2067", nameof (ReadCapturedParameter), "tParameter", nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => tParameter.RequiresAll ();
+ }
+
+ public static void ReadCapturedParameterAfterWrite (Type tParameter)
+ {
+ tParameter = GetWithPublicMethods ();
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2067", "tParameter", nameof (DataFlowTypeExtensions.RequiresPublicMethods),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => tParameter.RequiresPublicMethods ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ // analyzer clears all local state, but trimmer doesn't
+ ProducedBy = ProducedBy.Trimmer)]
+ static void ReadCapturedVariableWithUnhoistedLocals ()
+ {
+ Type t = GetWithPublicMethods ();
+ Type notCaptured = GetWithPublicFields ();
+ LocalFunction ();
+ notCaptured.RequiresAll ();
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => t.RequiresAll ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ // We include all writes, including ones that can't reach the local function invocation.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ static void WriteCapturedVariable ()
+ {
+ Type t = GetWithPublicFields ();
+ LocalFunction ();
+ t.RequiresAll ();
+
+ void LocalFunction () => t = GetWithPublicMethods ();
+ }
+
+ public static void Test ()
+ {
+ WarningsInBody ();
+ WarningsInBodyUnused ();
+ ReadCapturedVariable ();
+ ReadMergedCapturedVariable ();
+ ReadCapturedVariableInMultipleBranches ();
+ ReadCapturedVariableInMultipleBranchesDistinct ();
+ ReadCapturedVariableInMultipleFunctions ();
+ ReadCapturedVariableInCallGraphCycle ();
+ ReadCapturedVariableWithBackwardsBranch ();
+ ReadCapturedParameter (null);
+ ReadCapturedParameterAfterWrite (null);
+ ReadCapturedVariableWithUnhoistedLocals ();
+ WriteCapturedVariable ();
+ }
+ }
+
+ class Lambda
+ {
+ static void WarningsInBody ()
+ {
+ var lambda =
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ () => {
+ Type t = GetWithPublicMethods ();
+ t.RequiresAll ();
+ };
+
+ lambda ();
+ }
+
+ static void WarningsInBodyUnused ()
+ {
+ var lambda =
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ () => {
+ Type t = GetWithPublicMethods ();
+ t.RequiresAll ();
+ };
+ }
+
+ static void ReadCapturedVariable ()
+ {
+ Type t = GetWithPublicMethods ();
+ Action lambda =
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ () => t.RequiresAll ();
+ lambda ();
+ }
+
+ static void ReadCapturedVariableAfterWriteAfterDefinition ()
+ {
+ Type t = GetWithPublicFields ();
+
+ Action lambda =
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ () => t.RequiresAll ();
+
+ t = GetWithPublicMethods ();
+ lambda ();
+ }
+
+ public static void ReadCapturedParameter (Type tParameter)
+ {
+ var lambda =
+ [ExpectedWarning ("IL2067", nameof (ReadCapturedParameter), "tParameter", nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ () => tParameter.RequiresAll ();
+
+ lambda ();
+ }
+
+ public static void ReadCapturedParameterAfterWrite (Type tParameter)
+ {
+ tParameter = GetWithPublicMethods ();
+ var lambda =
+ // We produce dataflow warnings for the unknown parameter even though it has been overwritten
+ // with a value that satisfies the requirement.
+ [ExpectedWarning ("IL2067", "tParameter", nameof (DataFlowTypeExtensions.RequiresPublicMethods),
+ ProducedBy = ProducedBy.Trimmer)]
+ () => tParameter.RequiresPublicMethods ();
+ lambda ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ static void ReadCapturedVariableWithUnhoistedLocals ()
+ {
+ Type t = GetWithPublicMethods ();
+ Type notCaptured = GetWithPublicFields ();
+ Action lambda =
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ () => t.RequiresAll ();
+ lambda ();
+ notCaptured.RequiresAll ();
+ }
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ // We include all writes, including ones that can't reach the local function invocation.
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ static void WriteCapturedVariable ()
+ {
+ Type t = GetWithPublicFields ();
+ Action lambda = () => t = GetWithPublicMethods ();
+ lambda ();
+ t.RequiresAll ();
+ }
+
+ public static void Test ()
+ {
+ WarningsInBody ();
+ WarningsInBodyUnused ();
+ ReadCapturedVariable ();
+ ReadCapturedVariableAfterWriteAfterDefinition ();
+ ReadCapturedParameter (null);
+ ReadCapturedParameterAfterWrite (null);
+ ReadCapturedVariableWithUnhoistedLocals ();
+ WriteCapturedVariable ();
+ }
+ }
+
+ class Complex
+ {
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
+ ProducedBy = ProducedBy.Trimmer)]
+ // Linker merges branches going forward
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), CompilerGeneratedCode = true,
+ ProducedBy = ProducedBy.Trimmer)]
+ static IEnumerable<int> IteratorWithLocalFunctions ()
+ {
+ Type t = GetWithPublicMethods ();
+ LocalFunction ();
+
+ yield return 0;
+
+ LocalFunction ();
+ t = GetWithPublicFields ();
+ LocalFunction ();
+ t.RequiresAll ();
+
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicMethods), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2072", nameof (GetWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll),
+ ProducedBy = ProducedBy.Trimmer)]
+ void LocalFunction () => t.RequiresAll ();
+ }
+
+ public static void Test ()
+ {
+ IteratorWithLocalFunctions ();
+ }
+ }
+
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
+ static Type GetAll () => null;
+
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
+ static Type GetWithPublicMethods () => null;
+
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)]
+ static Type GetWithPublicFields () => null;
+
+ static Type GetUnknownType () => null;
+
+ static async Task<int> MethodAsync ()
+ {
+ return await Task.FromResult (0);
+ }
+
+ [RequiresUnreferencedCode ("RUC")]
+ static void RUCMethod () { }
+
+ struct TestStruct
+ {
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)]
+ public Type TypeWithPublicFields => null;
+ }
+ }
+} \ No newline at end of file