Skip to content

Commit 7102706

Browse files
authored
Support field access on variables of type Enum (#105524)
Follow-up to #105351 This adds support for the case when a variable is of type Enum and there are no generics involved, so the following no longer produces trim warnings: ```csharp static void M(Enum v) { v.GetType().GetFields(); } ``` Fixes #105506
1 parent c1fdef4 commit 7102706

File tree

4 files changed

+41
-11
lines changed

4 files changed

+41
-11
lines changed

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ private partial bool TryHandleIntrinsic (
390390
// currently it won't do.
391391

392392
TypeDesc? staticType = (valueNode as IValueWithStaticType)?.StaticType?.Type;
393+
if (staticType?.IsByRef == true)
394+
{
395+
staticType = ((ByRefType)staticType).ParameterType;
396+
}
393397
if (staticType is null || (!staticType.IsDefType && !staticType.IsArray))
394398
{
395399
DynamicallyAccessedMemberTypes annotation = default;
@@ -432,6 +436,10 @@ private partial bool TryHandleIntrinsic (
432436
// we will also make it just work, even if the annotation doesn't match the usage.
433437
AddReturnValue(new SystemTypeValue(staticType));
434438
}
439+
else if (staticType.IsTypeOf("System", "Enum"))
440+
{
441+
AddReturnValue(_reflectionMarker.Annotations.GetMethodReturnValue(calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.PublicFields));
442+
}
435443
else
436444
{
437445
Debug.Assert(staticType is MetadataType || staticType.IsArray);

src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ private partial bool TryHandleIntrinsic (
113113
// where a parameter is annotated and if something in the method sets a specific known type to it
114114
// we will also make it just work, even if the annotation doesn't match the usage.
115115
AddReturnValue (new SystemTypeValue (new (staticType)));
116+
} else if (staticType.IsTypeOf ("System", "Enum")) {
117+
AddReturnValue (FlowAnnotations.Instance.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.PublicFields));
116118
} else {
117119
var annotation = FlowAnnotations.GetTypeAnnotation (staticType);
118120
AddReturnValue (FlowAnnotations.Instance.GetMethodReturnValue (calledMethod, _isNewObj, annotation));

src/tools/illink/src/linker/Linker.Dataflow/HandleCallAction.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ private partial bool TryHandleIntrinsic (
120120
// currently it won't do.
121121

122122
TypeReference? staticType = (valueNode as IValueWithStaticType)?.StaticType?.Type;
123+
if (staticType?.IsByReference == true)
124+
staticType = ((ByReferenceType) staticType).ElementType;
123125
TypeDefinition? staticTypeDef = staticType?.ResolveToTypeDefinition (_context);
124126
if (staticType is null || staticTypeDef is null) {
125127
DynamicallyAccessedMemberTypes annotation = default;
@@ -153,6 +155,8 @@ private partial bool TryHandleIntrinsic (
153155
// where a parameter is annotated and if something in the method sets a specific known type to it
154156
// we will also make it just work, even if the annotation doesn't match the usage.
155157
AddReturnValue (new SystemTypeValue (staticType));
158+
} else if (staticTypeDef.IsTypeOf ("System", "Enum")) {
159+
AddReturnValue (_context.Annotations.FlowAnnotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.PublicFields));
156160
} else {
157161
// Make sure the type is marked (this will mark it as used via reflection, which is sort of true)
158162
// This should already be true for most cases (method params, fields, ...), but just in case

src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ public static void Test ()
9797
class EnumTypeSatisfiesPublicFields
9898
{
9999
[Kept]
100-
[ExpectedWarning ("IL2072")]
101100
static void ParameterType (Enum instance)
102101
{
103102
instance.GetType ().RequiresPublicFields ();
@@ -113,7 +112,6 @@ class FieldType
113112
public FieldType (Enum instance) => field = instance;
114113

115114
[Kept]
116-
[ExpectedWarning ("IL2072")]
117115
public void Test ()
118116
{
119117
field.GetType ().RequiresPublicFields ();
@@ -134,18 +132,36 @@ static Enum ReturnType ()
134132
}
135133

136134
[Kept]
137-
[ExpectedWarning ("IL2072")]
138135
static void TestReturnType ()
139136
{
140137
ReturnType ().GetType ().RequiresPublicFields ();
141138
}
142139

140+
[Kept]
141+
static void OutParameter (out Enum value)
142+
{
143+
value = EnumType.Value;
144+
}
145+
146+
[Kept]
147+
// Analyzer doesn't assign a value to the out parameter after calling the OutParameter method,
148+
// so when it looks up the value of the local 'value', it returns an empty value, and the
149+
// GetType intrinsic handling can't see that the out param satisfies the public fields requirement.
150+
// Similar for the other cases below.
151+
[ExpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101734")]
152+
static void TestOutParameter ()
153+
{
154+
OutParameter (out var value);
155+
value.GetType ().RequiresPublicFields ();
156+
}
157+
143158
[Kept]
144159
public static void Test ()
145160
{
146161
ParameterType (EnumType.Value);
147162
new FieldType (EnumType.Value).Test ();
148163
TestReturnType ();
164+
TestOutParameter ();
149165
}
150166
}
151167

@@ -173,10 +189,10 @@ public static void TestAccessFromType ()
173189

174190
// Note: this doesn't warn for ILLink as a consequence of https://github.com/dotnet/runtime/issues/105345.
175191
// ILLink sees the field type as a generic parameter, whereas the other tools see it as System.Enum.
176-
// The special handling that treats Enum as satisfying PublicFields only applies to generic parameter constraints,
177-
// so ILLink doesn't warn here. Once this 105345 is fixed, ILLink should match the warning behavior of ILC
178-
// here and in the similar cases below.
179-
[ExpectedWarning ("IL2072", Tool.NativeAot | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/105345")]
192+
// The other tools don't warn because of the built-in handling for variables of type System.Enum,
193+
// and ILLink doesn't warn because this goes through the case that handles generic parameters constrained to be Enum.
194+
// When https://github.com/dotnet/runtime/issues/105345 is fixed this should go through the built-in handling for
195+
// System.Enum, like it does for ILC and the analyzer.
180196
static void TestAccessTypeGenericParameterAsField ()
181197
{
182198
TypeGenericParameterAsField<Enum>.field.GetType ().RequiresPublicFields ();
@@ -214,7 +230,7 @@ public static void TestAccessFromType ()
214230
}
215231
}
216232

217-
[ExpectedWarning ("IL2072", Tool.NativeAot | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/105345")]
233+
// Note: this happens to work for ILLink due to https://github.com/dotnet/runtime/issues/105345.
218234
static void TestAccessTypeGenericParameterAsReturnType ()
219235
{
220236
TypeGenericParameterAsReturnType<Enum>.Method ().GetType ().RequiresPublicFields ();
@@ -230,15 +246,15 @@ public static void Method (out T instance)
230246
}
231247

232248
[Kept]
233-
[ExpectedWarning ("IL2072")]
249+
[ExpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101734")]
234250
public static void TestAccessFromType ()
235251
{
236252
Method (out var instance);
237253
instance.GetType ().RequiresPublicFields ();
238254
}
239255
}
240256

241-
[ExpectedWarning ("IL2072")]
257+
[ExpectedWarning ("IL2072", Tool.Analyzer, "https://github.com/dotnet/runtime/issues/101734")]
242258
static void TestAccessTypeGenericParameterAsOutParam ()
243259
{
244260
TypeGenericParameterAsOutParam<Enum>.Method (out var instance);
@@ -259,7 +275,7 @@ static T MethodGenericParameterAsReturnType<T> () where T : Enum
259275
}
260276

261277
[Kept]
262-
[ExpectedWarning ("IL2072", Tool.NativeAot | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/105345")]
278+
// Note: this happens to work for ILLink due to https://github.com/dotnet/runtime/issues/105345.
263279
static void TestMethodGenericParameterAsReturnType ()
264280
{
265281
MethodGenericParameterAsReturnType<Enum> ().GetType ().RequiresPublicFields ();

0 commit comments

Comments
 (0)