From 226107b9117b9d166e38dd00e30f9ab54399e658 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 15 Jun 2022 09:28:50 -0700 Subject: Analyze implicit indexer reference operations (#2839) Adds support for `IImplicitIndexerReferenceOperation`, which represents an implicit access to an indexer that uses `System.Index`. Implicit means that there is no `System.Index` accessor in IL, but the compiler supports `System.Index` access via an existing indexer (for example one that takes int) for types that satisfy certain criteria. See https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/ranges#implicit-index-support for details. This operation only showed up in the CFG with a more recent version of the Roslyn APIs, so this includes an update to match the one used in dotnet/runtime. This resulted in a few changes to the generated code that required tweaking some of the test validation: - Delegate cache fields are emitted. This reuses an existing attribute originally designed for mcs, but it has been updated to check for these compiler-generated fields. - `.ThrowSwitchExpressionException` is emitted for an implicit unhandled case in switch expressions. This change includes a new attribute to check that this is kept in a few of the tests. --- .../DataFlow/NullableAnnotations.cs | 1 + .../DataFlow/PropertyDataFlow.cs | 82 ++++++++++++++++++++++ 2 files changed, 83 insertions(+) (limited to 'test/Mono.Linker.Tests.Cases/DataFlow') diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs index d19a1fb82..90c24fd9f 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs @@ -11,6 +11,7 @@ using DAMT = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; namespace Mono.Linker.Tests.Cases.DataFlow { [ExpectedNoWarnings] + [KeptPrivateImplementationDetails ("ThrowSwitchExpressionException")] class NullableAnnotations { [Kept] diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs index 2128b8e41..15508baca 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs @@ -45,6 +45,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow BasePropertyAccess.Test (); AccessReturnedInstanceProperty.Test (); + + ExplicitIndexerAccess.Test (); + ImplicitIndexerAccess.Test (); } [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] @@ -653,6 +656,85 @@ namespace Mono.Linker.Tests.Cases.DataFlow } } + class ExplicitIndexerAccess + { + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + Type this[Index idx] { + get => throw new NotImplementedException (); + set => throw new NotImplementedException (); + } + + [ExpectedWarning ("IL2072", "this[Index].get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2072", "Item.get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = ProducedBy.Trimmer)] + static void TestRead (ExplicitIndexerAccess instance = null) + { + instance[new Index (1)].RequiresAll (); + } + + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "this[Index].set", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "Item.set", ProducedBy = ProducedBy.Trimmer)] + static void TestWrite (ExplicitIndexerAccess instance = null) + { + instance[^1] = GetTypeWithPublicConstructors (); + } + + public static void Test () + { + TestRead (); + TestWrite (); + } + } + + class ImplicitIndexerAccess + { + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + Type this[int idx] { + get => throw new NotImplementedException (); + set => throw new NotImplementedException (); + } + + int Length => throw new NotImplementedException (); + + [ExpectedWarning ("IL2072", "this[Int32].get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2072", "Item.get", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = ProducedBy.Trimmer)] + static void TestRead (ImplicitIndexerAccess instance = null) + { + instance[new Index (1)].RequiresAll (); + } + + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "this[Int32].set", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), "Item.set", ProducedBy = ProducedBy.Trimmer)] + static void TestWrite (ImplicitIndexerAccess instance = null) + { + instance[^1] = GetTypeWithPublicConstructors (); + } + + [ExpectedWarning ("IL2072", nameof (GetUnknownType), "this[Int32].set", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), "Item.set", ProducedBy = ProducedBy.Trimmer)] + static void TestNullCoalescingAssignment (ImplicitIndexerAccess instance = null) + { + instance[new Index (1)] ??= GetUnknownType (); + } + + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] + static void TestSpanIndexerAccess (int start = 0, int end = 3) + { + Span bytes = stackalloc byte[4] { 1, 2, 3, 4 }; + bytes[^4] = 0; // This calls the get indexer which has a ref return. + int index = bytes[0]; + Type[] types = new Type[] { GetUnknownType () }; + types[index].RequiresAll (); + } + + public static void Test () + { + TestRead (); + TestWrite (); + TestNullCoalescingAssignment (); + TestSpanIndexerAccess (); + } + } + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] private static Type GetTypeWithPublicParameterlessConstructor () { -- cgit v1.2.3