diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index 072433e7925d9..43eb4c95152f4 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -148,18 +148,18 @@ public override void Initialize (AnalysisContext context) static void VerifyMemberOnlyApplyToTypesOrStrings (SymbolAnalysisContext context, ISymbol member) { var location = GetPrimaryLocation (member.Locations); - if (member is IFieldSymbol field && field.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !field.Type.IsTypeInterestingForDataflow ()) + if (member is IFieldSymbol field && field.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !field.Type.IsTypeInterestingForDataflow (isByRef: field.RefKind is not RefKind.None)) context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnFieldCanOnlyApplyToTypesOrStrings), location, member.GetDisplayName ())); else if (member is IMethodSymbol method) { - if (method.GetDynamicallyAccessedMemberTypesOnReturnType () != DynamicallyAccessedMemberTypes.None && !method.ReturnType.IsTypeInterestingForDataflow ()) + if (method.GetDynamicallyAccessedMemberTypesOnReturnType () != DynamicallyAccessedMemberTypes.None && !method.ReturnType.IsTypeInterestingForDataflow (isByRef: method.ReturnsByRef)) context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings), location, member.GetDisplayName ())); - if (method.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !method.ContainingType.IsTypeInterestingForDataflow ()) + if (method.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !method.ContainingType.IsTypeInterestingForDataflow (isByRef: false)) context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersIsNotAllowedOnMethods), location)); foreach (var parameter in method.Parameters) { - if (parameter.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !parameter.Type.IsTypeInterestingForDataflow ()) + if (parameter.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !parameter.Type.IsTypeInterestingForDataflow (isByRef: parameter.RefKind is not RefKind.None)) context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnMethodParameterCanOnlyApplyToTypesOrStrings), location, parameter.GetDisplayName (), member.GetDisplayName ())); } - } else if (member is IPropertySymbol property && property.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !property.Type.IsTypeInterestingForDataflow ()) { + } else if (member is IPropertySymbol property && property.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None && !property.Type.IsTypeInterestingForDataflow (isByRef: property.ReturnsByRef)) { context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings), location, member.GetDisplayName ())); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs index 9ca91613173ee..5e4c0c9f38e2c 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs @@ -16,16 +16,19 @@ private enum HierarchyFlags IsSystemReflectionIReflect = 0x02, } - public static bool IsTypeInterestingForDataflow (this ITypeSymbol type) + public static bool IsTypeInterestingForDataflow (this ITypeSymbol type, bool isByRef) { - if (type.SpecialType == SpecialType.System_String) + if (type.SpecialType is SpecialType.System_String && !isByRef) return true; - var flags = GetFlags (type); + if (type is not INamedTypeSymbol namedType) + return false; + + var flags = GetFlags (namedType); return IsSystemType (flags) || IsSystemReflectionIReflect (flags); } - private static HierarchyFlags GetFlags (ITypeSymbol type) + private static HierarchyFlags GetFlags (INamedTypeSymbol type) { HierarchyFlags flags = 0; if (type.IsTypeOf (WellKnownType.System_Reflection_IReflect)) { diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index 2d9cb6cd84160..ef504c72238a7 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -121,8 +121,8 @@ public override MultiValue VisitConversion (IConversionOperation operation, Stat { var value = base.VisitConversion (operation, state); - if (operation.OperatorMethod != null) - return operation.OperatorMethod.ReturnType.IsTypeInterestingForDataflow () ? new MethodReturnValue (operation.OperatorMethod, isNewObj: false) : value; + if (operation.OperatorMethod is IMethodSymbol method) + return method.ReturnType.IsTypeInterestingForDataflow (isByRef: method.ReturnsByRef) ? new MethodReturnValue (method, isNewObj: false) : value; // TODO - is it possible to have annotation on the operator method parameters? // if so, will these be checked here? @@ -346,7 +346,7 @@ public override void HandleReturnValue (MultiValue returnValue, IOperation opera if (OwningSymbol is not IMethodSymbol method) return; - if (method.ReturnType.IsTypeInterestingForDataflow ()) { + if (method.ReturnType.IsTypeInterestingForDataflow (isByRef: method.ReturnsByRef)) { var returnParameter = new MethodReturnValue (method, isNewObj: false); TrimAnalysisPatterns.Add ( diff --git a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs index cb3ea98d4483e..5f106d831e675 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -151,7 +151,14 @@ public bool IsTypeInterestingForDataflow (TypeReference typeReference) if (typeReference.MetadataType == MetadataType.String) return true; - TypeDefinition? type = _context.TryResolve (typeReference); + // ByRef over an interesting type is itself interesting + if (typeReference.IsByReference) + typeReference = ((ByReferenceType) typeReference).ElementType; + + if (!typeReference.IsNamedType ()) + return false; + + TypeDefinition? type = typeReference.ResolveToTypeDefinition (_context); return type != null && ( _hierarchyInfo.IsSystemType (type) || _hierarchyInfo.IsSystemReflectionIReflect (type)); diff --git a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs index 35f6ca0bd04d4..855691ba3ecd9 100644 --- a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs @@ -408,6 +408,27 @@ public static TypeReference WithoutModifiers (this TypeReference type) return type; } + // Check whether this type represents a "named type" (i.e. a type that has a name and can be resolved to a TypeDefinition), + // not an array, pointer, byref, or generic parameter. Conceptually this is supposed to represent the same idea as Roslyn's + // INamedTypeSymbol, or ILC's DefType/MetadataType. + public static bool IsNamedType (this TypeReference typeReference) { + if (typeReference.IsDefinition || typeReference.IsGenericInstance) + return true; + + if (typeReference.IsArray || typeReference.IsByReference || typeReference.IsPointer || typeReference.IsGenericParameter) + return false; + + // Shouldn't get called for these cases + Debug.Assert (!typeReference.IsFunctionPointer); + Debug.Assert (!typeReference.IsRequiredModifier); + Debug.Assert (!typeReference.IsOptionalModifier); + Debug.Assert (!typeReference.IsPinned); + Debug.Assert (!typeReference.IsSentinel); + + Debug.Assert (typeReference.GetType () == typeof (TypeReference)); + return true; + } + // Array types that are dynamically accessed should resolve to System.Array instead of its element type - which is what Cecil resolves to. // Any data flow annotations placed on a type parameter which receives an array type apply to the array itself. None of the members in its // element type should be marked. diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs index c2e5fd1367734..b6d5eed8170f1 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs @@ -31,6 +31,7 @@ public static void Main () typeof (AttributeConstructorDataflow).GetMethod ("Main").GetCustomAttribute (typeof (KeepsPublicConstructorAttribute)); typeof (AttributeConstructorDataflow).GetMethod ("Main").GetCustomAttribute (typeof (KeepsPublicMethodsAttribute)); AllOnSelf.Test (); + AnnotationOnTypeArray.Test (); } [Kept] @@ -160,6 +161,43 @@ public void Method () { } } } + [Kept] + class AnnotationOnTypeArray + { + [Kept] + [KeptBaseType (typeof (Attribute))] + class AttributeRequiresTypeArrayAttribute : Attribute + { + [Kept] + [ExpectedWarning ("IL2098")] + [UnexpectedWarning ("IL2067", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + public AttributeRequiresTypeArrayAttribute ( + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + Type[] types) + { + RequirePublicFields (types); + } + + [Kept] + [ExpectedWarning ("IL2098")] + static void RequirePublicFields ( + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + Type[] types) + { + } + } + + [Kept] + [KeptAttributeAttribute (typeof (AttributeRequiresTypeArrayAttribute))] + [UnexpectedWarning ("IL2062", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + [AttributeRequiresTypeArray (new Type[] { typeof (int) })] + public static void Test () { + typeof (AnnotationOnTypeArray).GetMethod ("Test").GetCustomAttribute (typeof (AttributeRequiresTypeArrayAttribute)); + } + } + [Kept] [KeptBaseType (typeof (Attribute))] class TypeArrayAttribute : Attribute diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs index 43d0ac582cc17..677d2f9baae52 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs @@ -345,11 +345,52 @@ static void TestFlowOutOfField () } [UnexpectedWarning ("IL2074", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] - public static void Test () { + static void TestUnsupportedType () { var t = GetUnsupportedTypeInstance (); unsupportedTypeInstance = t; TestFlowOutOfField (); } + + ref struct StringRef + { + [ExpectedWarning ("IL2097")] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public ref string stringRef; + + [UnexpectedWarning ("IL2069", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + public StringRef (ref string s) + { + stringRef = ref s; + } + + static string GetString () => null; + + [ExpectedWarning ("IL2098")] + static void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + ref string s) + { + } + + [UnexpectedWarning ("IL2077", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + void TestFlowOutOfField () + { + RequirePublicFields (ref stringRef); + } + + public static void Test () + { + string s = GetString (); + var stringRef = new StringRef (ref s); + stringRef.TestFlowOutOfField (); + } + } + + public static void Test () + { + TestUnsupportedType (); + StringRef.Test (); + } } class WriteArrayField diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs index bd3c5c4adfbbe..01ead5a86c16d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs @@ -13,6 +13,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow // - so the main validation is done by the ExpectedWarning attributes. [SkipKeptItemsValidation] [ExpectedNoWarnings] + [SetupCompileArgument ("/unsafe")] [SetupLinkerArgument ("--keep-metadata", "parametername")] public class MethodParametersDataFlow { @@ -44,6 +45,7 @@ public static void Main () TestVarargsMethod (typeof (TestType), __arglist (0, 1, 2)); #endif AnnotationOnUnsupportedParameter.Test (); + AnnotationOnByRefParameter.Test (); WriteCapturedParameter.Test (); } @@ -237,7 +239,7 @@ static void TestVarargsMethod ([DynamicallyAccessedMembers (DynamicallyAccessedM class AnnotationOnUnsupportedParameter { - class UnsupportedType () + class UnsupportedType { } @@ -260,10 +262,152 @@ static void RequirePublicFields ( } [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] - public static void Test () { + static void TestUnsupportedType () + { var t = GetUnsupportedTypeInstance (); RequirePublicMethods (t); } + + static Type[] GetTypeArray () => null; + + [ExpectedWarning ("IL2098")] + [UnexpectedWarning ("IL2067", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static void RequirePublicMethods ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + Type[] types) + { + RequirePublicFields (types); + } + + [ExpectedWarning ("IL2098")] + static void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + Type[] types) + { + } + + [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static void TestTypeArray () + { + var types = GetTypeArray (); + RequirePublicMethods (types); + } + + static unsafe Type* GetTypePtr () => throw null; + + [ExpectedWarning ("IL2098")] + [UnexpectedWarning ("IL2067", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static unsafe void RequirePublicMethods ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + Type* typePtr) + { + RequirePublicFields (typePtr); + } + + [ExpectedWarning ("IL2098")] + static unsafe void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + Type* typePtr) + { + } + + [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static unsafe void TestTypePointer () + { + var typePtr = GetTypePtr (); + RequirePublicMethods (typePtr); + } + + static T GetTConstrainedToType () where T : Type => throw null; + + [ExpectedWarning ("IL2098")] + [UnexpectedWarning ("IL2067", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static void RequirePublicMethods ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + T t) where T : Type + { + RequirePublicFields (t); + } + + [ExpectedWarning ("IL2098")] + static void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + T t) where T : Type + { + } + + [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static void TestTypeGenericParameter () + { + var t = GetTConstrainedToType (); + RequirePublicMethods (t); + } + + static ref string GetStringRef () => throw null; + + [ExpectedWarning ("IL2098")] + [UnexpectedWarning ("IL2067", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static void RequirePublicMethods ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + ref string stringRef) + { + RequirePublicFields (ref stringRef); + } + + [ExpectedWarning ("IL2098")] + static void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + ref string stringRef) + { + } + + [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + static void TestStringRef () + { + var stringRef = GetStringRef (); + RequirePublicMethods (ref stringRef); + } + + public static void Test () { + TestUnsupportedType (); + TestTypeArray (); + TestTypePointer (); + TestTypeGenericParameter (); + TestStringRef (); + } + } + + class AnnotationOnByRefParameter + { + static ref Type GetTypeRef () => throw null; + + [ExpectedWarning ("IL2067")] + [ExpectedWarning ("IL2067", Tool.NativeAot | Tool.Trimmer, "https://github.com/dotnet/runtime/issues/101734")] + static void RequirePublicMethods ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + ref Type typeRef) + { + RequirePublicFields (ref typeRef); + } + + static void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + ref Type typeRef) + { + } + + [ExpectedWarning ("IL2062", Tool.NativeAot | Tool.Trimmer, "https://github.com/dotnet/runtime/issues/101734")] + [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101734")] + static void TestTypeRef () + { + var typeRef = GetTypeRef (); + RequirePublicMethods (ref typeRef); + } + + public static void Test () + { + TestTypeRef (); + } } class WriteCapturedParameter diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs index bc94f0813be38..abb26a1aa8e04 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs @@ -226,9 +226,32 @@ static void TestCtorReturnValue () { RequirePublicFields (t); } + class StringRefReturnValue + { + string f; + + ref string GetRefString () => ref f; + + [ExpectedWarning ("IL2098")] + static void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + ref string s) + { + } + + [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + public static void Test () + { + var instance = new StringRefReturnValue (); + ref var s = ref instance.GetRefString (); + RequirePublicFields (ref s); + } + } + public static void Test () { TestMethodReturnValue (); TestCtorReturnValue (); + StringRefReturnValue.Test (); } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs index c2273a6d87cbf..935db2d2aa8ab 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs @@ -32,7 +32,6 @@ public static void Main () instance.PropertyPublicParameterlessConstructorWithExplicitAccessors = null; instance.PropertyPublicConstructorsWithExplicitAccessors = null; instance.PropertyNonPublicConstructorsWithExplicitAccessors = null; - _ = PropertyWithUnsupportedType; TestAutomaticPropagation (); @@ -49,6 +48,8 @@ public static void Main () ExplicitIndexerAccess.Test (); ImplicitIndexerAccess.Test (); + + AnnotationOnUnsupportedType.Test (); } [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] @@ -57,9 +58,6 @@ public static void Main () [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] static Type StaticPropertyWithPublicConstructor { get; set; } - [ExpectedWarning ("IL2099", nameof (PropertyWithUnsupportedType))] - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] - static object PropertyWithUnsupportedType { get; set; } [ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresNonPublicConstructors))] private void ReadFromInstanceProperty () @@ -868,6 +866,41 @@ public static void Test () } } + class AnnotationOnUnsupportedType + { + [ExpectedWarning ("IL2099", nameof (PropertyWithUnsupportedType))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + static object PropertyWithUnsupportedType { get; set; } + + class StringRefProperty + { + string f; + + ref string RefString => ref f; + + [ExpectedWarning ("IL2098")] + static void RequirePublicFields ( + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + ref string s) + { + } + + [UnexpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101211")] + public static void Test () + { + var instance = new StringRefProperty (); + ref var s = ref instance.RefString; + RequirePublicFields (ref s); + } + } + + public static void Test () + { + _ = PropertyWithUnsupportedType; + StringRefProperty.Test (); + } + } + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] private static Type GetTypeWithPublicParameterlessConstructor () {