Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dataflow analysis for GetNestedType #109814

Merged
merged 9 commits into from
Nov 20, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public void Reflection (string t)
case "UnsafeAccessor":
case "TypeUsedViaReflection":
case "RunClassConstructor":
case "NestedTypeUsedViaReflection":
Run (t);
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,15 @@ ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
break;
}

const DynamicallyAccessedMemberTypes ImplicitNestedTypeAccessLevel =
DynamicallyAccessedMemberTypesEx.PublicConstructorsWithInherited | DynamicallyAccessedMemberTypesEx.NonPublicConstructorsWithInherited |
DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypesEx.NonPublicMethodsWithInherited |
DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypesEx.NonPublicFieldsWithInherited |
DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypesEx.NonPublicPropertiesWithInherited |
DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypesEx.NonPublicEventsWithInherited |
DynamicallyAccessedMemberTypesEx.PublicNestedTypesWithInherited | DynamicallyAccessedMemberTypesEx.NonPublicNestedTypesWithInherited |
DynamicallyAccessedMemberTypes.Interfaces;

BindingFlags? bindingFlags;
if (calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
Expand All @@ -554,8 +563,8 @@ ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);

// We only applied the annotation based on binding flags, so we will keep the necessary types
// but we will not keep anything on them. So the return value has no known annotations on it
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.None));
// and we keep the set of implicitly available members on them.
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, ImplicitNestedTypeAccessLevel));
}
}
} else if (value is NullValue) {
Expand All @@ -567,11 +576,11 @@ ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers

// If the input is an annotated value which has All - we can propagate that to the return value
// since All applies recursively to all nested type (see MarkStep.MarkEntireType).
// Otherwise we only mark the nested type itself, nothing on it, so the return value has no annotation on it.
// Otherwise we mark the nested type with implicitly available members on it.
if (value is ValueWithDynamicallyAccessedMembers { DynamicallyAccessedMemberTypes: DynamicallyAccessedMemberTypes.All })
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.All));
else
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.None));
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, ImplicitNestedTypeAccessLevel));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Helpers;

namespace Mono.Linker.Tests.Cases.Reflection
{
Expand All @@ -28,6 +30,9 @@ public static void Main ()
UnsupportedBindingFlags.Test ();

MemberOnNestedType.Test ();
MemberOnUnknownBindingFlagsAndName.Test (BindingFlags.Public, "DoesntMatter");

GetNestedTypeOnAnnotatedLocation.Test (null);
}

[Kept]
Expand Down Expand Up @@ -202,6 +207,31 @@ public static void Test ()
}
}

static class MemberOnUnknownBindingFlagsAndName
{
[Kept]
public static class PublicNestedType
{
[Kept]
public static int SomeField;

[Kept]
private static void SomeMethod() { }
}

[Kept]
[ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresAll))]
public static void Test (BindingFlags bindingFlags, string name)
{
// Since the binding flags and name are not known trimming tools should mark all nested types on the type
// It should also mark the members that are expected and satisfy the requirements
typeof (MemberOnUnknownBindingFlagsAndName).GetNestedType (name, bindingFlags).RequiresPublicFields ();

// Should warn
typeof (MemberOnUnknownBindingFlagsAndName).GetNestedType (name, bindingFlags).RequiresAll ();
}
}

[Kept]
static class IgnoreCaseBindingFlags
{
Expand Down Expand Up @@ -245,5 +275,18 @@ public static void Test ()
_ = typeof (UnsupportedBindingFlags).GetNestedType ("SuppressChangeTypeNestedType", BindingFlags.SuppressChangeType);
}
}

[Kept]
private class GetNestedTypeOnAnnotatedLocation
{
[ExpectedWarning ("IL2072", nameof (DataFlowTypeExtensions) + "." + nameof (DataFlowTypeExtensions.RequiresAll))]
[Kept]
public static void Test ([KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute)), DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes)] Type t)
{
t.GetNestedType ("DoesntMatter").RequiresPublicConstructors ();
t.GetNestedType ("DoesntMatter").RequiresNonPublicMethodsWithInherited ();
t.GetNestedType ("DoesntMatter").RequiresAll ();
}
}
}
}
Loading