diff options
author | Sven Boemer <sbomer@gmail.com> | 2022-06-15 19:28:50 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-15 19:28:50 +0300 |
commit | 226107b9117b9d166e38dd00e30f9ab54399e658 (patch) | |
tree | 410de8da2b0f1555d977b78938f7ced082a32c72 /test/Mono.Linker.Tests.Cases | |
parent | 2abcee1070e38d2994a25777023dfa61615ea498 (diff) |
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.
- `<PrivateImplementationDetails>.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.
Diffstat (limited to 'test/Mono.Linker.Tests.Cases')
15 files changed, 99 insertions, 11 deletions
diff --git a/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeCtorOnEvent.cs b/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeCtorOnEvent.cs index 6b9c5ff8e..eaf9a4866 100644 --- a/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeCtorOnEvent.cs +++ b/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeCtorOnEvent.cs @@ -14,7 +14,7 @@ namespace Mono.Linker.Tests.Cases.Attributes.Csc [KeptTypeInAssembly ("LibraryWithType.dll", typeof (TypeDefinedInReference))] [RemovedMemberInAssembly ("LibraryWithType.dll", typeof (TypeDefinedInReference), "Unused()")] [KeptMemberInAssembly ("LibraryWithAttribute.dll", typeof (AttributeDefinedInReference), ".ctor(System.Type)")] - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (FooOnMyEvent))] public class OnlyTypeUsedInAssemblyIsTypeOnAttributeCtorOnEvent { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeFieldOnEvent.cs b/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeFieldOnEvent.cs index 9026e6048..d069585c0 100644 --- a/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeFieldOnEvent.cs +++ b/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributeFieldOnEvent.cs @@ -15,7 +15,7 @@ namespace Mono.Linker.Tests.Cases.Attributes.Csc [RemovedMemberInAssembly ("LibraryWithType.dll", typeof (TypeDefinedInReference), "Unused()")] [KeptMemberInAssembly ("LibraryWithAttribute.dll", typeof (AttributeDefinedInReference), ".ctor()")] [KeptMemberInAssembly ("LibraryWithAttribute.dll", typeof (AttributeDefinedInReference), "FieldType")] - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (FooOnMyEvent))] public class OnlyTypeUsedInAssemblyIsTypeOnAttributeFieldOnEvent { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributePropertyOnEvent.cs b/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributePropertyOnEvent.cs index 5f1791948..83466e847 100644 --- a/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributePropertyOnEvent.cs +++ b/test/Mono.Linker.Tests.Cases/Attributes/Csc/OnlyTypeUsedInAssemblyIsTypeOnAttributePropertyOnEvent.cs @@ -15,7 +15,7 @@ namespace Mono.Linker.Tests.Cases.Attributes.Csc [RemovedMemberInAssembly ("LibraryWithType.dll", typeof (TypeDefinedInReference), "Unused()")] [KeptMemberInAssembly ("LibraryWithAttribute.dll", typeof (AttributeDefinedInReference), ".ctor()")] [KeptMemberInAssembly ("LibraryWithAttribute.dll", typeof (AttributeDefinedInReference), "set_PropertyType(System.Type)")] - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (FooOnMyEvent))] public class OnlyTypeUsedInAssemblyIsTypeOnAttributePropertyOnEvent { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UnusedAttributeTypeOnEventIsRemoved.cs b/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UnusedAttributeTypeOnEventIsRemoved.cs index ff8775974..c05e9ad30 100644 --- a/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UnusedAttributeTypeOnEventIsRemoved.cs +++ b/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UnusedAttributeTypeOnEventIsRemoved.cs @@ -5,7 +5,7 @@ using Mono.Linker.Tests.Cases.Expectations.Metadata; namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed { [SetupLinkerArgument ("--used-attrs-only", "true")] - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (Tmp_Something))] class UnusedAttributeTypeOnEventIsRemoved { static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UsedAttributeTypeOnEventIsKept.cs b/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UsedAttributeTypeOnEventIsKept.cs index 27d50d3cd..0a5e3cfe3 100644 --- a/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UsedAttributeTypeOnEventIsKept.cs +++ b/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/UsedAttributeTypeOnEventIsKept.cs @@ -5,7 +5,7 @@ using Mono.Linker.Tests.Cases.Expectations.Metadata; namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed { [SetupLinkerArgument ("--used-attrs-only", "true")] - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (Tmp_Something))] class UsedAttributeTypeOnEventIsKept { static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Basic/DelegateBeginInvokeEndInvokePair.cs b/test/Mono.Linker.Tests.Cases/Basic/DelegateBeginInvokeEndInvokePair.cs index d39ab89d9..99e8e90ae 100644 --- a/test/Mono.Linker.Tests.Cases/Basic/DelegateBeginInvokeEndInvokePair.cs +++ b/test/Mono.Linker.Tests.Cases/Basic/DelegateBeginInvokeEndInvokePair.cs @@ -5,6 +5,9 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Basic { + [KeptDelegateCacheField ("0", nameof (Method))] + [KeptDelegateCacheField ("1", nameof (Method))] + [KeptDelegateCacheField ("2", nameof (Method))] class DelegateBeginInvokeEndInvokePair { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Basic/UsedEventIsKept.cs b/test/Mono.Linker.Tests.Cases/Basic/UsedEventIsKept.cs index 8453f1624..490ffa348 100644 --- a/test/Mono.Linker.Tests.Cases/Basic/UsedEventIsKept.cs +++ b/test/Mono.Linker.Tests.Cases/Basic/UsedEventIsKept.cs @@ -3,8 +3,7 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Basic { - [KeptDelegateCacheField ("0")] - [KeptDelegateCacheField ("1")] + [KeptDelegateCacheField ("0", nameof (Tmp_Bar))] class UsedEventIsKept { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsKept.cs b/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsKept.cs index 099b92ab2..47e45e75e 100644 --- a/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsKept.cs +++ b/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsKept.cs @@ -3,7 +3,7 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Basic { - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (Bar_Ping))] class UsedEventOnInterfaceIsKept { static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsRemovedWhenUsedFromClass.cs b/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsRemovedWhenUsedFromClass.cs index 464db7008..10555f041 100644 --- a/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsRemovedWhenUsedFromClass.cs +++ b/test/Mono.Linker.Tests.Cases/Basic/UsedEventOnInterfaceIsRemovedWhenUsedFromClass.cs @@ -3,7 +3,7 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Basic { - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (Bar_Ping))] class UsedEventOnInterfaceIsRemovedWhenUsedFromClass { static void Main () 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<byte> 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 () { diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithEvent.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithEvent.cs index e8856be3b..ec4a75670 100644 --- a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithEvent.cs +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithEvent.cs @@ -2,7 +2,7 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.BaseProvidesInterfaceMember { - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (EventMethod))] public class GenericInterfaceWithEvent { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/SimpleEvent.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/SimpleEvent.cs index 11e5860a6..98597a4b2 100644 --- a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/SimpleEvent.cs +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/SimpleEvent.cs @@ -2,7 +2,7 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.BaseProvidesInterfaceMember { - [KeptDelegateCacheField ("0")] + [KeptDelegateCacheField ("0", nameof (EventMethod))] public class SimpleEvent { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs index 10ac90435..5489497a8 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs @@ -10,6 +10,7 @@ namespace Mono.Linker.Tests.Cases.Reflection [SetupCSharpCompilerToUse ("csc")] [Reference ("System.Core.dll")] [ExpectedNoWarnings] + [KeptPrivateImplementationDetails ("ThrowSwitchExpressionException")] public class ExpressionCallString { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs index 906f56ab4..5bec60d50 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs @@ -9,6 +9,8 @@ namespace Mono.Linker.Tests.Cases.Reflection { [KeptMember (".cctor()")] [ExpectedNoWarnings ()] + [KeptDelegateCacheField ("0", nameof (AssemblyResolver))] + [KeptDelegateCacheField ("1", nameof (GetTypeFromAssembly))] public class TypeUsedViaReflection { public static void Main () |