diff options
author | Vitek Karas <10670590+vitek-karas@users.noreply.github.com> | 2022-03-01 21:03:18 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-01 21:03:18 +0300 |
commit | 8c0df916d86bfd223bc0cd4830611fa8611bb72f (patch) | |
tree | 878e66432914af97e8e8896943e821eb03ce9590 | |
parent | a8f953291e17745ee920d37c5143ab7556031301 (diff) |
Share intrinsics for Expression.Property and Field (#2671)
Shares two more intrinsics, with supporting infra.
Fixed a bug in the intrinsics - passing null to the name of a property/field will throw at runtime, so no need to validate anything.
Modifies the existing tests to add warnings, since that is the only verifyable behavior for the analyzer.
11 files changed, 194 insertions, 100 deletions
diff --git a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index e525c52c3..fa7a8ca8a 100644 --- a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -37,6 +37,7 @@ namespace ILLink.RoslynAnalyzer diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.UnrecognizedTypeInRuntimeHelpersRunClassConstructor)); + diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined)); return diagDescriptorsArrayBuilder.ToImmutable (); diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs index ebb14a434..6e743f9b7 100644 --- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs +++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using ILLink.RoslynAnalyzer; @@ -79,6 +80,18 @@ namespace ILLink.Shared.TrimAnalysis // TODO: Does the analyzer need to do something here? private partial void MarkType (TypeProxy type) { } + private partial bool MarkAssociatedProperty (MethodProxy method) + { + if (method.Method.MethodKind == MethodKind.PropertyGet || method.Method.MethodKind == MethodKind.PropertySet) { + var property = (IPropertySymbol) method.Method.AssociatedSymbol!; + Debug.Assert (property != null); + ReflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForProperty (_diagnosticContext, property!); + return true; + } + + return false; + } + private partial string GetContainingSymbolDisplayName () => _operation.FindContainingSymbol (_owningSymbol).GetDisplayName (); } } diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs index b5663698a..d190370a3 100644 --- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs @@ -24,7 +24,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis GetDiagnosticsForField (diagnosticContext, field); break; case IPropertySymbol property: - GetDiagnosticsForProperty (diagnosticContext, property); + GetReflectionAccessDiagnosticsForProperty (diagnosticContext, property); break; /* Skip Type and InterfaceImplementation marking since doesnt seem relevant for diagnostic generation case ITypeSymbol nestedType: @@ -56,7 +56,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis internal void GetReflectionAccessDiagnosticsForPropertiesOnTypeHierarchy (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags) { foreach (var prop in typeSymbol.GetPropertiesOnTypeHierarchy (p => p.Name == name, bindingFlags)) - GetDiagnosticsForProperty (diagnosticContext, prop); + GetReflectionAccessDiagnosticsForProperty (diagnosticContext, prop); } static void ReportRequiresUnreferencedCodeDiagnostic (in DiagnosticContext diagnosticContext, AttributeData requiresAttributeData, ISymbol member) @@ -85,7 +85,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis } } - static void GetDiagnosticsForProperty (in DiagnosticContext diagnosticContext, IPropertySymbol propertySymbol) + internal static void GetReflectionAccessDiagnosticsForProperty (in DiagnosticContext diagnosticContext, IPropertySymbol propertySymbol) { if (propertySymbol.SetMethod is not null) GetReflectionAccessDiagnosticsForMethod (diagnosticContext, propertySymbol.SetMethod); diff --git a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs index 216d5a105..002c213b9 100644 --- a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs +++ b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using ILLink.Shared.DataFlow; @@ -479,6 +480,66 @@ namespace ILLink.Shared.TrimAnalysis } break; + // + // System.Linq.Expressions.Expression + // + // static Property (Expression, MethodInfo) + // + case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo"): { + foreach (var value in argumentValues[1]) { + if (value is SystemReflectionMethodBaseValue methodBaseValue) { + // We have one of the accessors for the property. The Expression.Property will in this case search + // for the matching PropertyInfo and store that. So to be perfectly correct we need to mark the + // respective PropertyInfo as "accessed via reflection". + if (MarkAssociatedProperty (methodBaseValue.MethodRepresented)) + continue; + } else if (value == NullValue.Instance) { + continue; + } + + // In all other cases we may not even know which type this is about, so there's nothing we can do + // report it as a warning. + _diagnosticContext.AddDiagnostic (DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined, + GetMethodParameterValue (calledMethod, 1, DynamicallyAccessedMemberTypes.None).GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ()); + } + } + break; + + // + // System.Linq.Expressions.Expression + // + // static Field (Expression, Type, String) + // static Property (Expression, Type, String) + // + case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property: { + DynamicallyAccessedMemberTypes memberTypes = fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property + ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties + : DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields; + + var targetValue = GetMethodParameterValue (calledMethod, 1, memberTypes); + foreach (var value in argumentValues[1]) { + if (value is SystemTypeValue systemTypeValue) { + foreach (var stringParam in argumentValues[2]) { + if (stringParam is KnownStringValue stringValue) { + BindingFlags bindingFlags = argumentValues[0].AsSingleValue () is NullValue ? BindingFlags.Static : BindingFlags.Default; + if (fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property) { + MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags); + } else { + MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags); + } + } else if (stringParam is NullValue) { + // Null name will always throw, so there's nothing to do + } else { + _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue); + } + } + } else { + _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue); + } + } + } + break; + case IntrinsicId.None: methodReturnValue = MultiValueLattice.Top; return false; @@ -637,6 +698,8 @@ namespace ILLink.Shared.TrimAnalysis private partial void MarkType (TypeProxy type); + private partial bool MarkAssociatedProperty (MethodProxy method); + // Only used for internal diagnostic purposes (not even for warning messages) private partial string GetContainingSymbolDisplayName (); } diff --git a/src/linker/Linker.Dataflow/HandleCallAction.cs b/src/linker/Linker.Dataflow/HandleCallAction.cs index b88e6d8e9..de8dcf8f2 100644 --- a/src/linker/Linker.Dataflow/HandleCallAction.cs +++ b/src/linker/Linker.Dataflow/HandleCallAction.cs @@ -86,6 +86,16 @@ namespace ILLink.Shared.TrimAnalysis private partial void MarkType (TypeProxy type) => _reflectionMethodBodyScanner.MarkType (_analysisContext, type.Type); + private partial bool MarkAssociatedProperty (MethodProxy method) + { + if (method.Method.TryGetProperty (out PropertyDefinition? propertyDefinition)) { + _reflectionMethodBodyScanner.MarkProperty (_analysisContext, propertyDefinition); + return true; + } + + return false; + } + private partial string GetContainingSymbolDisplayName () => _callingMethodDefinition.GetDisplayName (); } } diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index be5306e55..61325ae6b 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -287,7 +287,9 @@ namespace Mono.Linker.Dataflow || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty: case IntrinsicId.Type_GetMember: case IntrinsicId.Type_GetMethod: - case IntrinsicId.Type_GetNestedType: { + case IntrinsicId.Type_GetNestedType: + case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo"): + case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property: { var instanceValue = MultiValueLattice.Top; IReadOnlyList<MultiValue> parameterValues = methodParams; if (calledMethodDefinition.HasImplicitThis ()) { @@ -415,67 +417,6 @@ namespace Mono.Linker.Dataflow // // System.Linq.Expressions.Expression // - // static Property (Expression, MethodInfo) - // - case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType (1, "System.Reflection.MethodInfo"): { - foreach (var value in methodParams[1]) { - if (value is SystemReflectionMethodBaseValue methodBaseValue) { - // We have one of the accessors for the property. The Expression.Property will in this case search - // for the matching PropertyInfo and store that. So to be perfectly correct we need to mark the - // respective PropertyInfo as "accessed via reflection". - if (methodBaseValue.MethodRepresented.Method.TryGetProperty (out PropertyDefinition? propertyDefinition)) { - MarkProperty (analysisContext, propertyDefinition); - continue; - } - } else if (value == NullValue.Instance) { - continue; - } - - // In all other cases we may not even know which type this is about, so there's nothing we can do - // report it as a warning. - analysisContext.ReportWarning (DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined, - DiagnosticUtilities.GetParameterNameForErrorMessage (calledMethodDefinition.Parameters[1]), - DiagnosticUtilities.GetMethodSignatureDisplayName (calledMethodDefinition)); - } - } - break; - - // - // System.Linq.Expressions.Expression - // - // static Field (Expression, Type, String) - // static Property (Expression, Type, String) - // - case var fieldOrPropertyInstrinsic when fieldOrPropertyInstrinsic == IntrinsicId.Expression_Field || fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property: { - DynamicallyAccessedMemberTypes memberTypes = fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property - ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties - : DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields; - - var targetValue = GetMethodParameterValue (calledMethodDefinition, 1, memberTypes); - foreach (var value in methodParams[1]) { - if (value is SystemTypeValue systemTypeValue) { - foreach (var stringParam in methodParams[2]) { - if (stringParam is KnownStringValue stringValue) { - BindingFlags bindingFlags = methodParams[0].AsSingleValue () is NullValue ? BindingFlags.Static : BindingFlags.Default; - if (fieldOrPropertyInstrinsic == IntrinsicId.Expression_Property) { - MarkPropertiesOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, filter: p => p.Name == stringValue.Contents, bindingFlags); - } else { - MarkFieldsOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, filter: f => f.Name == stringValue.Contents, bindingFlags); - } - } else { - RequireDynamicallyAccessedMembers (analysisContext, value, targetValue); - } - } - } else { - RequireDynamicallyAccessedMembers (analysisContext, value, targetValue); - } - } - } - break; - - // - // System.Linq.Expressions.Expression - // // static New (Type) // case IntrinsicId.Expression_New: { @@ -1151,7 +1092,7 @@ namespace Mono.Linker.Dataflow _markStep.MarkFieldVisibleToReflection (field, new DependencyInfo (dependencyKind, analysisContext.Origin.Provider)); } - void MarkProperty (in AnalysisContext analysisContext, PropertyDefinition property, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection) + internal void MarkProperty (in AnalysisContext analysisContext, PropertyDefinition property, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection) { _markStep.MarkPropertyVisibleToReflection (property, new DependencyInfo (dependencyKind, analysisContext.Origin.Provider)); } diff --git a/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs b/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs index 7dc1e1639..0e12517ab 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs @@ -55,6 +55,12 @@ namespace ILLink.RoslynAnalyzer.Tests } [Fact] + public Task ExpressionFieldString () + { + return RunTest (); + } + + [Fact] public Task ExpressionNewType () { return RunTest (allowMissingWarnings: true); @@ -63,7 +69,13 @@ namespace ILLink.RoslynAnalyzer.Tests [Fact] public Task ExpressionPropertyMethodInfo () { - return RunTest (allowMissingWarnings: true); + return RunTest (); + } + + [Fact] + public Task ExpressionPropertyString () + { + return RunTest (); } [Fact] diff --git a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs index 2ef192d11..6e1bf553d 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs @@ -44,18 +44,6 @@ namespace ILLink.RoslynAnalyzer.Tests } [Fact] - public Task ExpressionFieldString () - { - return RunTest (allowMissingWarnings: true); - } - - [Fact] - public Task ExpressionPropertyString () - { - return RunTest (allowMissingWarnings: true); - } - - [Fact] public Task ObjectGetTypeLibraryMode () { return RunTest (allowMissingWarnings: true); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index 3f1396000..1a7e121dc 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -10,13 +10,16 @@ namespace Mono.Linker.Tests.Cases.Reflection [ExpectedNoWarnings] public class ExpressionFieldString { + [ExpectedWarning ("IL2110", nameof (StaticWithDAM))] + [ExpectedWarning ("IL2110", "_publicFieldOnBase")] [ExpectedWarning ("IL2072", nameof (Expression) + "." + nameof (Expression.Field))] public static void Main () { - Expression.Field (Expression.Parameter (typeof (int), ""), typeof (ExpressionFieldString), "Field"); + Expression.Field (Expression.Parameter (typeof (int), ""), typeof (ExpressionFieldString), "InstanceField"); Expression.Field (null, typeof (ExpressionFieldString), "StaticField"); + Expression.Field (null, typeof (ExpressionFieldString), "StaticWithDAM"); // IL2110 Expression.Field (null, typeof (Derived), "_protectedFieldOnBase"); - Expression.Field (null, typeof (Derived), "_publicFieldOnBase"); + Expression.Field (null, typeof (Derived), "_publicFieldOnBase"); // IL2110 UnknownType.Test (); UnknownTypeNoAnnotation.Test (); UnknownString.Test (); @@ -29,13 +32,20 @@ namespace Mono.Linker.Tests.Cases.Reflection } [Kept] - private int Field; + private int InstanceField; [Kept] static private int StaticField; + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + static private Type StaticWithDAM; + private int UnusedField; + public static int StaticField1 { get => StaticField; set => StaticField = value; } + [Kept] static Type GetType () { @@ -142,7 +152,6 @@ namespace Mono.Linker.Tests.Cases.Reflection Expression.Field (null, typeof (Base), noValue); } - [Kept] class Base { @@ -150,7 +159,9 @@ namespace Mono.Linker.Tests.Cases.Reflection protected static bool _protectedFieldOnBase; [Kept] - public static bool _publicFieldOnBase; + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public static Type _publicFieldOnBase; } [Kept] diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs index b4d9613ae..b0de477dc 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyMethodInfo.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -32,10 +33,12 @@ namespace Mono.Linker.Tests.Cases.Reflection { [Kept] [KeptBackingField] - public static int StaticProperty { + public static int StaticPropertyExpressionAccess { [Kept] get; [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (StaticPropertyExpressionAccess))] set; } @@ -45,6 +48,8 @@ namespace Mono.Linker.Tests.Cases.Reflection [Kept] get; [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (StaticPropertyViaReflection))] set; } @@ -54,15 +59,19 @@ namespace Mono.Linker.Tests.Cases.Reflection [Kept] get; [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (StaticPropertyViaRuntimeMethod))] set; } [Kept] [KeptBackingField] - public int InstanceProperty { + public int InstancePropertyExpressionAccess { [Kept] get; [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (InstancePropertyExpressionAccess))] set; } @@ -72,18 +81,27 @@ namespace Mono.Linker.Tests.Cases.Reflection [Kept] get; [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (InstancePropertyViaReflection))] set; } [Kept] + // https://github.com/dotnet/linker/issues/2669 + [ExpectedWarning ("IL2026", nameof (StaticPropertyExpressionAccess), ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", nameof (StaticPropertyViaReflection))] + [ExpectedWarning ("IL2026", nameof (StaticPropertyViaRuntimeMethod))] + // https://github.com/dotnet/linker/issues/2669 + [ExpectedWarning ("IL2026", nameof (InstancePropertyExpressionAccess), ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", nameof (InstancePropertyViaReflection))] public static void Test () { - Expression<Func<int>> staticGetter = () => StaticProperty; + Expression<Func<int>> staticGetter = () => StaticPropertyExpressionAccess; Expression.Property (null, typeof (PropertyGetter).GetMethod ("get_StaticPropertyViaReflection")); PropertyGetter instance = new PropertyGetter (); - Expression<Func<PropertyGetter, int>> instanceGetter = i => i.InstanceProperty; + Expression<Func<PropertyGetter, int>> instanceGetter = i => i.InstancePropertyExpressionAccess; Expression.Property (Expression.New (typeof (PropertyGetter)), typeof (PropertyGetter).GetMethod ("get_InstancePropertyViaReflection")); @@ -97,8 +115,10 @@ namespace Mono.Linker.Tests.Cases.Reflection { [Kept] [KeptBackingField] - public static int StaticProperty { + public static int StaticPropertyReflectionAccess { [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (StaticPropertyReflectionAccess))] get; [Kept] set; @@ -108,6 +128,8 @@ namespace Mono.Linker.Tests.Cases.Reflection [KeptBackingField] public static int StaticPropertyViaRuntimeMethod { [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (StaticPropertyViaRuntimeMethod))] get; [Kept] set; @@ -115,21 +137,26 @@ namespace Mono.Linker.Tests.Cases.Reflection [Kept] [KeptBackingField] - public int InstanceProperty { + public int InstancePropertyReflectionAccess { [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (InstancePropertyReflectionAccess))] get; [Kept] set; } [Kept] + [ExpectedWarning ("IL2026", nameof (StaticPropertyReflectionAccess))] + [ExpectedWarning ("IL2026", nameof (StaticPropertyViaRuntimeMethod))] + [ExpectedWarning ("IL2026", nameof (InstancePropertyReflectionAccess))] public static void Test () { - Expression.Property (null, typeof (PropertySetter).GetMethod ("set_StaticProperty")); + Expression.Property (null, typeof (PropertySetter).GetMethod ("set_StaticPropertyReflectionAccess")); Expression.Property (null, typeof (PropertySetter).GetRuntimeMethod ("set_StaticPropertyViaRuntimeMethod", Type.EmptyTypes)); - Expression.Property (Expression.New (typeof (PropertySetter)), typeof (PropertySetter).GetMethod ("set_InstanceProperty")); + Expression.Property (Expression.New (typeof (PropertySetter)), typeof (PropertySetter).GetMethod ("set_InstancePropertyReflectionAccess")); } } @@ -158,10 +185,12 @@ namespace Mono.Linker.Tests.Cases.Reflection { [Kept] [KeptBackingField] - public static int StaticProperty { + public static int FirstStaticProperty { [Kept] get; [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (FirstStaticProperty))] set; } @@ -171,16 +200,20 @@ namespace Mono.Linker.Tests.Cases.Reflection [Kept] get; [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (SecondStaticProperty))] set; } [Kept] + [ExpectedWarning ("IL2026", nameof (FirstStaticProperty))] + [ExpectedWarning ("IL2026", nameof (SecondStaticProperty))] public static void Test (int p) { MethodInfo mi; switch (p) { case 0: - mi = typeof (MultipleMethods).GetMethod ("get_StaticProperty"); + mi = typeof (MultipleMethods).GetMethod ("get_FirstStaticProperty"); break; case 1: mi = typeof (MultipleMethods).GetMethod ("get_SecondStaticProperty"); @@ -195,7 +228,8 @@ namespace Mono.Linker.Tests.Cases.Reflection } [Kept] - [ExpectedWarning ("IL2103", nameof (Expression) + "." + nameof (Expression.Property))] + // https://github.com/dotnet/linker/issues/2670 + [ExpectedWarning ("IL2103", nameof (Expression) + "." + nameof (Expression.Property), ProducedBy = ProducedBy.Trimmer)] static void TestUnknownMethod (MethodInfo mi) { Expression.Property (null, mi); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index 9f9f8591d..ff8530d5c 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -12,11 +12,14 @@ namespace Mono.Linker.Tests.Cases.Reflection [ExpectedNoWarnings] public class ExpressionPropertyString { + [ExpectedWarning ("IL2026", nameof (BasicProperty))] + [ExpectedWarning ("IL2111", "ProtectedPropertyOnBase")] + [ExpectedWarning ("IL2026", "PublicPropertyOnBase")] [ExpectedWarning ("IL2072", nameof (Expression) + "." + nameof (Expression.Property))] public static void Main () { - Expression.Property (Expression.Parameter (typeof (int), ""), typeof (ExpressionPropertyString), "Property"); - Expression.Property (null, typeof (ExpressionPropertyString), "StaticProperty"); + Expression.Property (Expression.Parameter (typeof (int), ""), typeof (ExpressionPropertyString), nameof (BasicProperty)); + Expression.Property (null, typeof (ExpressionPropertyString), nameof (StaticProperty)); Expression.Property (null, typeof (Derived), "ProtectedPropertyOnBase"); Expression.Property (null, typeof (Derived), "PublicPropertyOnBase"); UnknownType.Test (); @@ -30,13 +33,15 @@ namespace Mono.Linker.Tests.Cases.Reflection } [Kept] - private int Property { + private int BasicProperty { [Kept] [ExpectBodyModified] get; [Kept] [ExpectBodyModified] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (BasicProperty))] set; } @@ -159,11 +164,27 @@ namespace Mono.Linker.Tests.Cases.Reflection { [Kept] [KeptBackingField] - protected static bool ProtectedPropertyOnBase { [Kept] get; } + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + protected static Type ProtectedPropertyOnBase { + [Kept] + get; + + [Kept] + set; + } [Kept] [KeptBackingField] - public static bool PublicPropertyOnBase { [Kept] get; } + public static bool PublicPropertyOnBase { + [Kept] + get; + + [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (PublicPropertyOnBase))] + set; + } } [Kept] |