From 5e3f8d53a2b7fd54055babbe0290e14573fc2108 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:40:43 +0000 Subject: [PATCH 1/4] Add DelegateDataFlow tests for DAM analysis on Func/Action delegate types Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f8d36913-1346-4f8d-8514-eb398ffbc0e1 Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- .../DataFlowTests.cs | 6 + .../DataFlow/DelegateDataFlow.cs | 295 ++++++++++++++++++ 2 files changed, 301 insertions(+) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs index 3c3287cabab981..811566f7161ea9 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs @@ -148,6 +148,12 @@ public Task DependencyInjectionPattern() return RunTest(); } + [Fact] + public Task DelegateDataFlow() + { + return RunTest(); + } + [Fact] public Task DynamicDependencyDataflow() { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs new file mode 100644 index 00000000000000..5c0c660117d796 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs @@ -0,0 +1,295 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class DelegateDataFlow + { + public static void Main () + { + AnnotatedDelegateParameter.Test (); + AnnotatedDelegateFuncLikeParameter.Test (); + AnnotatedDelegateMultipleParameters.Test (); + AnnotatedDelegateWithAnnotatedParamAndUnannotatedReturn.Test (); + GenericDelegateWithAnnotatedTypeParameter.Test (); + ActionAndFuncWithAnnotatedLambda.Test (); + } + + // =================================================== + // Tests for custom delegate type with DAM-annotated parameter + // as field, property, and local variable — then invoked + // =================================================== + class AnnotatedDelegateParameter + { + delegate void DelegateWithAnnotatedParam ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type); + + // --- Field scenarios --- + + static DelegateWithAnnotatedParam _fieldDelegate; + + static void TestFieldInvokeWithMatchingAnnotation ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + _fieldDelegate (type); + } + + [ExpectedWarning ("IL2067", nameof (type), nameof (_fieldDelegate))] + static void TestFieldInvokeWithoutAnnotation (Type type) + { + _fieldDelegate (type); + } + + [ExpectedWarning ("IL2067", nameof (type), nameof (_fieldDelegate))] + static void TestFieldInvokeWithMismatchedAnnotation ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) + { + _fieldDelegate (type); + } + + static void TestFieldInvokeWithTypeOf () + { + _fieldDelegate (typeof (TestType)); + } + + // --- Property scenarios --- + + static DelegateWithAnnotatedParam DelegateProperty { get; set; } + + static void TestPropertyInvokeWithMatchingAnnotation ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + DelegateProperty (type); + } + + [ExpectedWarning ("IL2067", nameof (type), nameof (DelegateProperty))] + static void TestPropertyInvokeWithoutAnnotation (Type type) + { + DelegateProperty (type); + } + + // --- Local variable scenarios --- + + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] + static void TestLocalInvokeWithoutAnnotation (Type type) + { + DelegateWithAnnotatedParam local = _fieldDelegate; + local (type); + } + + public static void Test () + { + TestFieldInvokeWithMatchingAnnotation (typeof (TestType)); + TestFieldInvokeWithoutAnnotation (typeof (TestType)); + TestFieldInvokeWithMismatchedAnnotation (typeof (TestType)); + TestFieldInvokeWithTypeOf (); + TestPropertyInvokeWithMatchingAnnotation (typeof (TestType)); + TestPropertyInvokeWithoutAnnotation (typeof (TestType)); + TestLocalInvokeWithoutAnnotation (typeof (TestType)); + } + } + + // =================================================== + // Tests for Func-like delegate (parameter + return) with DAM on parameter + // =================================================== + class AnnotatedDelegateFuncLikeParameter + { + delegate string DelegateWithAnnotatedTypeParam ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type); + + static DelegateWithAnnotatedTypeParam _field; + + [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + static void TestFieldInvokeWithoutAnnotation (Type type) + { + _field (type); + } + + static void TestFieldInvokeWithMatchingAnnotation ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + _field (type); + } + + public static void Test () + { + TestFieldInvokeWithoutAnnotation (typeof (TestType)); + TestFieldInvokeWithMatchingAnnotation (typeof (TestType)); + } + } + + // =================================================== + // Tests for custom delegate types with multiple annotated parameters + // =================================================== + class AnnotatedDelegateMultipleParameters + { + delegate void DelegateWithTwoAnnotatedParams ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields); + + static DelegateWithTwoAnnotatedParams _field; + + static void TestMatchingAnnotations ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields) + { + _field (typeMethods, typeFields); + } + + [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + static void TestFirstParameterMismatched ( + Type type, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields) + { + _field (type, typeFields); + } + + [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + static void TestSecondParameterMismatched ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, + Type type) + { + _field (typeMethods, type); + } + + [ExpectedWarning ("IL2067", nameof (type1), nameof (_field))] + [ExpectedWarning ("IL2067", nameof (type2), nameof (_field))] + static void TestBothParametersMismatched (Type type1, Type type2) + { + _field (type1, type2); + } + + public static void Test () + { + TestMatchingAnnotations (typeof (TestType), typeof (TestType)); + TestFirstParameterMismatched (typeof (TestType), typeof (TestType)); + TestSecondParameterMismatched (typeof (TestType), typeof (TestType)); + TestBothParametersMismatched (typeof (TestType), typeof (TestType)); + } + } + + // =================================================== + // Tests for custom delegate with annotated parameter and unannotated return + // verifying both parameter and return value flow + // =================================================== + class AnnotatedDelegateWithAnnotatedParamAndUnannotatedReturn + { + delegate Type DelegateWithAnnotatedParam ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type); + + static DelegateWithAnnotatedParam _field; + + // Return is unannotated, so using it for PublicMethods should warn + [ExpectedWarning ("IL2072", nameof (_field), nameof (DataFlowTypeExtensions.RequiresPublicMethods))] + static void TestReturnValueUsedWithRequirement ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + _field (type).RequiresPublicMethods (); + } + + // Parameter is unannotated - should warn for parameter; return used without requirement - no extra warning + [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + static void TestParameterMismatch (Type type) + { + _ = _field (type); + } + + // Both: parameter mismatch + return value used with requirement + [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + [ExpectedWarning ("IL2072", nameof (_field), nameof (DataFlowTypeExtensions.RequiresPublicMethods))] + static void TestBothMismatched (Type type) + { + _field (type).RequiresPublicMethods (); + } + + public static void Test () + { + TestReturnValueUsedWithRequirement (typeof (TestType)); + TestParameterMismatch (typeof (TestType)); + TestBothMismatched (typeof (TestType)); + } + } + + // =================================================== + // Tests for generic delegate with DAM on the type parameter itself + // =================================================== + class GenericDelegateWithAnnotatedTypeParameter + { + delegate void DelegateWithGenericParam<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> (T value); + + static DelegateWithGenericParam _fieldInstantiatedWithType; + + [ExpectedWarning ("IL2067", nameof (type), nameof (_fieldInstantiatedWithType))] + static void TestFieldInvokeWithoutAnnotation (Type type) + { + _fieldInstantiatedWithType (type); + } + + static void TestFieldInvokeWithMatchingAnnotation ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + _fieldInstantiatedWithType (type); + } + + public static void Test () + { + TestFieldInvokeWithoutAnnotation (typeof (TestType)); + TestFieldInvokeWithMatchingAnnotation (typeof (TestType)); + } + } + + // =================================================== + // Tests for Action<> and Func<> with annotated lambda parameters + // This tests that the annotations on lambda parameters are tracked + // when creating delegates from lambdas with DAM annotations. + // =================================================== + class ActionAndFuncWithAnnotatedLambda + { + // Assigning a lambda with DAM-annotated parameter to Action + // should warn because Action's Invoke parameter has no DAM. + [ExpectedWarning ("IL2111")] + static void TestActionWithAnnotatedLambda () + { + Action a = ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => { }; + a (typeof (TestType)); + } + + // Same for Func + [ExpectedWarning ("IL2111")] + static void TestFuncWithAnnotatedLambda () + { + Func f = ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => t.ToString (); + f (typeof (TestType)); + } + + // Annotated local function assigned to Action + [ExpectedWarning ("IL2111")] + static void TestActionWithAnnotatedLocalFunction () + { + Action a = LocalFunction; + a (typeof (TestType)); + + void LocalFunction ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + } + } + + public static void Test () + { + TestActionWithAnnotatedLambda (); + TestFuncWithAnnotatedLambda (); + TestActionWithAnnotatedLocalFunction (); + } + } + + class TestType + { + } + } +} From 4bf6e143c5ddc431e9732c6f1e918b4813eefb66 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:23:29 +0000 Subject: [PATCH 2/4] Add DelegateDataFlow tests for DynamicallyAccessedMembers analysis on delegate fields/properties Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f8d36913-1346-4f8d-8514-eb398ffbc0e1 Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- .../DataFlow/DelegateDataFlow.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs index 5c0c660117d796..7571a0fe6293fe 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs @@ -18,7 +18,6 @@ public static void Main () AnnotatedDelegateFuncLikeParameter.Test (); AnnotatedDelegateMultipleParameters.Test (); AnnotatedDelegateWithAnnotatedParamAndUnannotatedReturn.Test (); - GenericDelegateWithAnnotatedTypeParameter.Test (); ActionAndFuncWithAnnotatedLambda.Test (); } @@ -40,13 +39,13 @@ static void TestFieldInvokeWithMatchingAnnotation ( _fieldDelegate (type); } - [ExpectedWarning ("IL2067", nameof (type), nameof (_fieldDelegate))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] static void TestFieldInvokeWithoutAnnotation (Type type) { _fieldDelegate (type); } - [ExpectedWarning ("IL2067", nameof (type), nameof (_fieldDelegate))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] static void TestFieldInvokeWithMismatchedAnnotation ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) { @@ -68,7 +67,7 @@ static void TestPropertyInvokeWithMatchingAnnotation ( DelegateProperty (type); } - [ExpectedWarning ("IL2067", nameof (type), nameof (DelegateProperty))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] static void TestPropertyInvokeWithoutAnnotation (Type type) { DelegateProperty (type); @@ -104,7 +103,7 @@ class AnnotatedDelegateFuncLikeParameter static DelegateWithAnnotatedTypeParam _field; - [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] static void TestFieldInvokeWithoutAnnotation (Type type) { _field (type); @@ -141,7 +140,7 @@ static void TestMatchingAnnotations ( _field (typeMethods, typeFields); } - [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] static void TestFirstParameterMismatched ( Type type, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields) @@ -149,7 +148,7 @@ static void TestFirstParameterMismatched ( _field (type, typeFields); } - [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] static void TestSecondParameterMismatched ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, Type type) @@ -157,8 +156,8 @@ static void TestSecondParameterMismatched ( _field (typeMethods, type); } - [ExpectedWarning ("IL2067", nameof (type1), nameof (_field))] - [ExpectedWarning ("IL2067", nameof (type2), nameof (_field))] + [ExpectedWarning ("IL2067", nameof (type1), "Invoke")] + [ExpectedWarning ("IL2067", nameof (type2), "Invoke")] static void TestBothParametersMismatched (Type type1, Type type2) { _field (type1, type2); From 4d7445836be45a35971739a8e200fbf605953f58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:58:56 +0000 Subject: [PATCH 3/4] Fix ExpectedWarning attributes to use Invoke and remove dead GenericDelegate test class Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/346454a4-d1ec-4c38-b03e-d5d6f8fa0155 Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- .../DataFlow/DelegateDataFlow.cs | 36 +++---------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs index 7571a0fe6293fe..def2f018c931be 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs @@ -184,7 +184,7 @@ delegate Type DelegateWithAnnotatedParam ( static DelegateWithAnnotatedParam _field; // Return is unannotated, so using it for PublicMethods should warn - [ExpectedWarning ("IL2072", nameof (_field), nameof (DataFlowTypeExtensions.RequiresPublicMethods))] + [ExpectedWarning ("IL2072", "Invoke", nameof (DataFlowTypeExtensions.RequiresPublicMethods))] static void TestReturnValueUsedWithRequirement ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { @@ -192,15 +192,15 @@ static void TestReturnValueUsedWithRequirement ( } // Parameter is unannotated - should warn for parameter; return used without requirement - no extra warning - [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] static void TestParameterMismatch (Type type) { _ = _field (type); } // Both: parameter mismatch + return value used with requirement - [ExpectedWarning ("IL2067", nameof (type), nameof (_field))] - [ExpectedWarning ("IL2072", nameof (_field), nameof (DataFlowTypeExtensions.RequiresPublicMethods))] + [ExpectedWarning ("IL2067", nameof (type), "Invoke")] + [ExpectedWarning ("IL2072", "Invoke", nameof (DataFlowTypeExtensions.RequiresPublicMethods))] static void TestBothMismatched (Type type) { _field (type).RequiresPublicMethods (); @@ -214,34 +214,6 @@ public static void Test () } } - // =================================================== - // Tests for generic delegate with DAM on the type parameter itself - // =================================================== - class GenericDelegateWithAnnotatedTypeParameter - { - delegate void DelegateWithGenericParam<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> (T value); - - static DelegateWithGenericParam _fieldInstantiatedWithType; - - [ExpectedWarning ("IL2067", nameof (type), nameof (_fieldInstantiatedWithType))] - static void TestFieldInvokeWithoutAnnotation (Type type) - { - _fieldInstantiatedWithType (type); - } - - static void TestFieldInvokeWithMatchingAnnotation ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) - { - _fieldInstantiatedWithType (type); - } - - public static void Test () - { - TestFieldInvokeWithoutAnnotation (typeof (TestType)); - TestFieldInvokeWithMatchingAnnotation (typeof (TestType)); - } - } - // =================================================== // Tests for Action<> and Func<> with annotated lambda parameters // This tests that the annotations on lambda parameters are tracked From fff2aebc98b000a011710814bfb77252daa567bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 23:10:08 +0000 Subject: [PATCH 4/4] Fix formatting to match sibling test file conventions (spaces, no space before parens) Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/346454a4-d1ec-4c38-b03e-d5d6f8fa0155 Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- .../DataFlow/DelegateDataFlow.cs | 510 +++++++++--------- 1 file changed, 255 insertions(+), 255 deletions(-) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs index def2f018c931be..803cebcef547e7 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/DelegateDataFlow.cs @@ -8,259 +8,259 @@ namespace Mono.Linker.Tests.Cases.DataFlow { - [SkipKeptItemsValidation] - [ExpectedNoWarnings] - public class DelegateDataFlow - { - public static void Main () - { - AnnotatedDelegateParameter.Test (); - AnnotatedDelegateFuncLikeParameter.Test (); - AnnotatedDelegateMultipleParameters.Test (); - AnnotatedDelegateWithAnnotatedParamAndUnannotatedReturn.Test (); - ActionAndFuncWithAnnotatedLambda.Test (); - } - - // =================================================== - // Tests for custom delegate type with DAM-annotated parameter - // as field, property, and local variable — then invoked - // =================================================== - class AnnotatedDelegateParameter - { - delegate void DelegateWithAnnotatedParam ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type); - - // --- Field scenarios --- - - static DelegateWithAnnotatedParam _fieldDelegate; - - static void TestFieldInvokeWithMatchingAnnotation ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) - { - _fieldDelegate (type); - } - - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestFieldInvokeWithoutAnnotation (Type type) - { - _fieldDelegate (type); - } - - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestFieldInvokeWithMismatchedAnnotation ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) - { - _fieldDelegate (type); - } - - static void TestFieldInvokeWithTypeOf () - { - _fieldDelegate (typeof (TestType)); - } - - // --- Property scenarios --- - - static DelegateWithAnnotatedParam DelegateProperty { get; set; } - - static void TestPropertyInvokeWithMatchingAnnotation ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) - { - DelegateProperty (type); - } - - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestPropertyInvokeWithoutAnnotation (Type type) - { - DelegateProperty (type); - } - - // --- Local variable scenarios --- - - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestLocalInvokeWithoutAnnotation (Type type) - { - DelegateWithAnnotatedParam local = _fieldDelegate; - local (type); - } - - public static void Test () - { - TestFieldInvokeWithMatchingAnnotation (typeof (TestType)); - TestFieldInvokeWithoutAnnotation (typeof (TestType)); - TestFieldInvokeWithMismatchedAnnotation (typeof (TestType)); - TestFieldInvokeWithTypeOf (); - TestPropertyInvokeWithMatchingAnnotation (typeof (TestType)); - TestPropertyInvokeWithoutAnnotation (typeof (TestType)); - TestLocalInvokeWithoutAnnotation (typeof (TestType)); - } - } - - // =================================================== - // Tests for Func-like delegate (parameter + return) with DAM on parameter - // =================================================== - class AnnotatedDelegateFuncLikeParameter - { - delegate string DelegateWithAnnotatedTypeParam ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type); - - static DelegateWithAnnotatedTypeParam _field; - - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestFieldInvokeWithoutAnnotation (Type type) - { - _field (type); - } - - static void TestFieldInvokeWithMatchingAnnotation ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) - { - _field (type); - } - - public static void Test () - { - TestFieldInvokeWithoutAnnotation (typeof (TestType)); - TestFieldInvokeWithMatchingAnnotation (typeof (TestType)); - } - } - - // =================================================== - // Tests for custom delegate types with multiple annotated parameters - // =================================================== - class AnnotatedDelegateMultipleParameters - { - delegate void DelegateWithTwoAnnotatedParams ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields); - - static DelegateWithTwoAnnotatedParams _field; - - static void TestMatchingAnnotations ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields) - { - _field (typeMethods, typeFields); - } - - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestFirstParameterMismatched ( - Type type, - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields) - { - _field (type, typeFields); - } - - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestSecondParameterMismatched ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, - Type type) - { - _field (typeMethods, type); - } - - [ExpectedWarning ("IL2067", nameof (type1), "Invoke")] - [ExpectedWarning ("IL2067", nameof (type2), "Invoke")] - static void TestBothParametersMismatched (Type type1, Type type2) - { - _field (type1, type2); - } - - public static void Test () - { - TestMatchingAnnotations (typeof (TestType), typeof (TestType)); - TestFirstParameterMismatched (typeof (TestType), typeof (TestType)); - TestSecondParameterMismatched (typeof (TestType), typeof (TestType)); - TestBothParametersMismatched (typeof (TestType), typeof (TestType)); - } - } - - // =================================================== - // Tests for custom delegate with annotated parameter and unannotated return - // verifying both parameter and return value flow - // =================================================== - class AnnotatedDelegateWithAnnotatedParamAndUnannotatedReturn - { - delegate Type DelegateWithAnnotatedParam ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type); - - static DelegateWithAnnotatedParam _field; - - // Return is unannotated, so using it for PublicMethods should warn - [ExpectedWarning ("IL2072", "Invoke", nameof (DataFlowTypeExtensions.RequiresPublicMethods))] - static void TestReturnValueUsedWithRequirement ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) - { - _field (type).RequiresPublicMethods (); - } - - // Parameter is unannotated - should warn for parameter; return used without requirement - no extra warning - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - static void TestParameterMismatch (Type type) - { - _ = _field (type); - } - - // Both: parameter mismatch + return value used with requirement - [ExpectedWarning ("IL2067", nameof (type), "Invoke")] - [ExpectedWarning ("IL2072", "Invoke", nameof (DataFlowTypeExtensions.RequiresPublicMethods))] - static void TestBothMismatched (Type type) - { - _field (type).RequiresPublicMethods (); - } - - public static void Test () - { - TestReturnValueUsedWithRequirement (typeof (TestType)); - TestParameterMismatch (typeof (TestType)); - TestBothMismatched (typeof (TestType)); - } - } - - // =================================================== - // Tests for Action<> and Func<> with annotated lambda parameters - // This tests that the annotations on lambda parameters are tracked - // when creating delegates from lambdas with DAM annotations. - // =================================================== - class ActionAndFuncWithAnnotatedLambda - { - // Assigning a lambda with DAM-annotated parameter to Action - // should warn because Action's Invoke parameter has no DAM. - [ExpectedWarning ("IL2111")] - static void TestActionWithAnnotatedLambda () - { - Action a = ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => { }; - a (typeof (TestType)); - } - - // Same for Func - [ExpectedWarning ("IL2111")] - static void TestFuncWithAnnotatedLambda () - { - Func f = ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => t.ToString (); - f (typeof (TestType)); - } - - // Annotated local function assigned to Action - [ExpectedWarning ("IL2111")] - static void TestActionWithAnnotatedLocalFunction () - { - Action a = LocalFunction; - a (typeof (TestType)); - - void LocalFunction ( - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) - { - } - } - - public static void Test () - { - TestActionWithAnnotatedLambda (); - TestFuncWithAnnotatedLambda (); - TestActionWithAnnotatedLocalFunction (); - } - } - - class TestType - { - } - } + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class DelegateDataFlow + { + public static void Main() + { + AnnotatedDelegateParameter.Test(); + AnnotatedDelegateFuncLikeParameter.Test(); + AnnotatedDelegateMultipleParameters.Test(); + AnnotatedDelegateWithAnnotatedParamAndUnannotatedReturn.Test(); + ActionAndFuncWithAnnotatedLambda.Test(); + } + + // =================================================== + // Tests for custom delegate type with DAM-annotated parameter + // as field, property, and local variable — then invoked + // =================================================== + class AnnotatedDelegateParameter + { + delegate void DelegateWithAnnotatedParam([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type); + + // --- Field scenarios --- + + static DelegateWithAnnotatedParam _fieldDelegate; + + static void TestFieldInvokeWithMatchingAnnotation( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + _fieldDelegate(type); + } + + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestFieldInvokeWithoutAnnotation(Type type) + { + _fieldDelegate(type); + } + + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestFieldInvokeWithMismatchedAnnotation( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type) + { + _fieldDelegate(type); + } + + static void TestFieldInvokeWithTypeOf() + { + _fieldDelegate(typeof(TestType)); + } + + // --- Property scenarios --- + + static DelegateWithAnnotatedParam DelegateProperty { get; set; } + + static void TestPropertyInvokeWithMatchingAnnotation( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + DelegateProperty(type); + } + + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestPropertyInvokeWithoutAnnotation(Type type) + { + DelegateProperty(type); + } + + // --- Local variable scenarios --- + + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestLocalInvokeWithoutAnnotation(Type type) + { + DelegateWithAnnotatedParam local = _fieldDelegate; + local(type); + } + + public static void Test() + { + TestFieldInvokeWithMatchingAnnotation(typeof(TestType)); + TestFieldInvokeWithoutAnnotation(typeof(TestType)); + TestFieldInvokeWithMismatchedAnnotation(typeof(TestType)); + TestFieldInvokeWithTypeOf(); + TestPropertyInvokeWithMatchingAnnotation(typeof(TestType)); + TestPropertyInvokeWithoutAnnotation(typeof(TestType)); + TestLocalInvokeWithoutAnnotation(typeof(TestType)); + } + } + + // =================================================== + // Tests for Func-like delegate (parameter + return) with DAM on parameter + // =================================================== + class AnnotatedDelegateFuncLikeParameter + { + delegate string DelegateWithAnnotatedTypeParam([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type); + + static DelegateWithAnnotatedTypeParam _field; + + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestFieldInvokeWithoutAnnotation(Type type) + { + _field(type); + } + + static void TestFieldInvokeWithMatchingAnnotation( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + _field(type); + } + + public static void Test() + { + TestFieldInvokeWithoutAnnotation(typeof(TestType)); + TestFieldInvokeWithMatchingAnnotation(typeof(TestType)); + } + } + + // =================================================== + // Tests for custom delegate types with multiple annotated parameters + // =================================================== + class AnnotatedDelegateMultipleParameters + { + delegate void DelegateWithTwoAnnotatedParams( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields); + + static DelegateWithTwoAnnotatedParams _field; + + static void TestMatchingAnnotations( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields) + { + _field(typeMethods, typeFields); + } + + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestFirstParameterMismatched( + Type type, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type typeFields) + { + _field(type, typeFields); + } + + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestSecondParameterMismatched( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type typeMethods, + Type type) + { + _field(typeMethods, type); + } + + [ExpectedWarning("IL2067", nameof(type1), "Invoke")] + [ExpectedWarning("IL2067", nameof(type2), "Invoke")] + static void TestBothParametersMismatched(Type type1, Type type2) + { + _field(type1, type2); + } + + public static void Test() + { + TestMatchingAnnotations(typeof(TestType), typeof(TestType)); + TestFirstParameterMismatched(typeof(TestType), typeof(TestType)); + TestSecondParameterMismatched(typeof(TestType), typeof(TestType)); + TestBothParametersMismatched(typeof(TestType), typeof(TestType)); + } + } + + // =================================================== + // Tests for custom delegate with annotated parameter and unannotated return + // verifying both parameter and return value flow + // =================================================== + class AnnotatedDelegateWithAnnotatedParamAndUnannotatedReturn + { + delegate Type DelegateWithAnnotatedParam( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type); + + static DelegateWithAnnotatedParam _field; + + // Return is unannotated, so using it for PublicMethods should warn + [ExpectedWarning("IL2072", "Invoke", nameof(DataFlowTypeExtensions.RequiresPublicMethods))] + static void TestReturnValueUsedWithRequirement( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + _field(type).RequiresPublicMethods(); + } + + // Parameter is unannotated - should warn for parameter; return used without requirement - no extra warning + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + static void TestParameterMismatch(Type type) + { + _ = _field(type); + } + + // Both: parameter mismatch + return value used with requirement + [ExpectedWarning("IL2067", nameof(type), "Invoke")] + [ExpectedWarning("IL2072", "Invoke", nameof(DataFlowTypeExtensions.RequiresPublicMethods))] + static void TestBothMismatched(Type type) + { + _field(type).RequiresPublicMethods(); + } + + public static void Test() + { + TestReturnValueUsedWithRequirement(typeof(TestType)); + TestParameterMismatch(typeof(TestType)); + TestBothMismatched(typeof(TestType)); + } + } + + // =================================================== + // Tests for Action<> and Func<> with annotated lambda parameters + // This tests that the annotations on lambda parameters are tracked + // when creating delegates from lambdas with DAM annotations. + // =================================================== + class ActionAndFuncWithAnnotatedLambda + { + // Assigning a lambda with DAM-annotated parameter to Action + // should warn because Action's Invoke parameter has no DAM. + [ExpectedWarning("IL2111")] + static void TestActionWithAnnotatedLambda() + { + Action a = ([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => { }; + a(typeof(TestType)); + } + + // Same for Func + [ExpectedWarning("IL2111")] + static void TestFuncWithAnnotatedLambda() + { + Func f = ([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) => t.ToString(); + f(typeof(TestType)); + } + + // Annotated local function assigned to Action + [ExpectedWarning("IL2111")] + static void TestActionWithAnnotatedLocalFunction() + { + Action a = LocalFunction; + a(typeof(TestType)); + + void LocalFunction( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + } + } + + public static void Test() + { + TestActionWithAnnotatedLambda(); + TestFuncWithAnnotatedLambda(); + TestActionWithAnnotatedLocalFunction(); + } + } + + class TestType + { + } + } }