in src/tools/illink/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs [68:1226]
private partial bool TryHandleIntrinsic (
MethodProxy calledMethod,
MultiValue instanceValue,
IReadOnlyList<MultiValue> argumentValues,
IntrinsicId intrinsicId,
out MultiValue? methodReturnValue);
bool TryHandleSharedIntrinsic (
MethodProxy calledMethod,
MultiValue instanceValue,
IReadOnlyList<MultiValue> argumentValues,
IntrinsicId intrinsicId,
out MultiValue? methodReturnValue)
{
MultiValue? returnValue = methodReturnValue = null;
bool requiresDataFlowAnalysis = _annotations.MethodRequiresDataFlowAnalysis (calledMethod);
var annotatedMethodReturnValue = _annotations.GetMethodReturnValue (calledMethod, _isNewObj);
Debug.Assert (requiresDataFlowAnalysis || annotatedMethodReturnValue.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.None);
switch (intrinsicId) {
case IntrinsicId.IntrospectionExtensions_GetTypeInfo:
Debug.Assert (instanceValue.IsEmpty ());
Debug.Assert (argumentValues.Count == 1);
// typeof(Foo).GetTypeInfo()... will be commonly present in code targeting
// the dead-end reflection refactoring. The call doesn't do anything and we
// don't want to lose the annotation.
returnValue = argumentValues[0];
break;
case IntrinsicId.TypeInfo_AsType:
// someType.AsType()... will be commonly present in code targeting
// the dead-end reflection refactoring. The call doesn't do anything and we
// don't want to lose the annotation.
returnValue = instanceValue;
break;
//
// UnderlyingSystemType
//
case IntrinsicId.Type_get_UnderlyingSystemType:
// This is identity for the purposes of the analysis.
returnValue = instanceValue;
break;
case IntrinsicId.Type_GetTypeFromHandle:
// Infrastructure piece to support "typeof(Foo)" in IL and direct calls everywhere
if (argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var value in argumentValues[0].AsEnumerable ()) {
AddReturnValue (value switch {
RuntimeTypeHandleForNullableSystemTypeValue nullableSystemType
=> new NullableSystemTypeValue (nullableSystemType.NullableType, nullableSystemType.UnderlyingTypeValue),
// When generating type handles from IL, the GenericParameterValue with DAM annotations is not available.
// Once we convert it to a Value with annotations here, there is no need to convert it back in get_TypeHandle
RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers nullableDamType when nullableDamType.UnderlyingTypeValue is RuntimeTypeHandleForGenericParameterValue underlyingGenericParameter
=> new NullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, _annotations.GetGenericParameterValue (underlyingGenericParameter.GenericParameter)),
// This should only happen if the code does something like typeof(Nullable<>).MakeGenericType(methodParameter).TypeHandle
RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers nullableDamType when nullableDamType.UnderlyingTypeValue is ValueWithDynamicallyAccessedMembers underlyingTypeValue
=> new NullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, underlyingTypeValue),
RuntimeTypeHandleValue typeHandle
=> new SystemTypeValue (typeHandle.RepresentedType),
RuntimeTypeHandleForGenericParameterValue genericParam
=> _annotations.GetGenericParameterValue (genericParam.GenericParameter),
RuntimeTypeHandleForValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
=> valueWithDynamicallyAccessedMembers.UnderlyingTypeValue,
_ => annotatedMethodReturnValue
});
}
break;
case IntrinsicId.Type_get_TypeHandle:
if (instanceValue.IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var value in instanceValue.AsEnumerable ()) {
if (value != NullValue.Instance)
AddReturnValue (value switch {
NullableSystemTypeValue nullableSystemType
=> new RuntimeTypeHandleForNullableSystemTypeValue (nullableSystemType.NullableType, nullableSystemType.UnderlyingTypeValue),
NullableValueWithDynamicallyAccessedMembers nullableDamType when nullableDamType.UnderlyingTypeValue is GenericParameterValue genericParam
=> new RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, new RuntimeTypeHandleForGenericParameterValue (genericParam.GenericParameter)),
NullableValueWithDynamicallyAccessedMembers nullableDamType
=> new RuntimeTypeHandleForNullableValueWithDynamicallyAccessedMembers (nullableDamType.NullableType, nullableDamType.UnderlyingTypeValue),
SystemTypeValue typeHandle
=> new RuntimeTypeHandleValue (typeHandle.RepresentedType),
GenericParameterValue genericParam
=> new RuntimeTypeHandleForGenericParameterValue (genericParam.GenericParameter),
ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
=> new RuntimeTypeHandleForValueWithDynamicallyAccessedMembers(valueWithDynamicallyAccessedMembers),
_ => annotatedMethodReturnValue
});
else
AddReturnValue (MultiValueLattice.Top);
}
break;
// System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle)
// System.Reflection.MethodBase.GetMethodFromHandle (RuntimeMethodHandle handle, RuntimeTypeHandle declaringType)
case IntrinsicId.MethodBase_GetMethodFromHandle: {
if (argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
// Infrastructure piece to support "ldtoken method -> GetMethodFromHandle"
foreach (var value in argumentValues[0].AsEnumerable ()) {
if (value is RuntimeMethodHandleValue methodHandle)
AddReturnValue (new SystemReflectionMethodBaseValue (methodHandle.RepresentedMethod));
else
AddReturnValue (annotatedMethodReturnValue);
}
}
break;
case IntrinsicId.MethodBase_get_MethodHandle: {
if (instanceValue.IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is SystemReflectionMethodBaseValue methodBaseValue)
AddReturnValue (new RuntimeMethodHandleValue (methodBaseValue.RepresentedMethod));
else
AddReturnValue (annotatedMethodReturnValue);
}
}
break;
case IntrinsicId.TypeDelegator_Ctor:
// This needs additional validation that the .ctor is called from a "newobj" instruction/operation
// so it can't be done easily in shared code yet.
case IntrinsicId.Array_Empty:
// Array.Empty<T> must for now be handled by the specific implementation since it requires instantiated generic method handling
case IntrinsicId.Object_GetType:
// Object.GetType requires additional handling by the caller to implement type hierarchy marking and related diagnostics
throw new NotImplementedException ("These intrinsics should be handled by the specific implementation: " + intrinsicId);
//
// GetInterface (String)
// GetInterface (String, bool)
//
case IntrinsicId.Type_GetInterface: {
if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, DynamicallyAccessedMemberTypes.Interfaces);
foreach (var value in instanceValue.AsEnumerable ()) {
foreach (var interfaceName in argumentValues[0].AsEnumerable ()) {
if (interfaceName == NullValue.Instance) {
// Throws on null string, so no return value.
AddReturnValue (MultiValueLattice.Top);
} else if (interfaceName is KnownStringValue stringValue && stringValue.Contents.Length == 0) {
AddReturnValue (NullValue.Instance);
} else {
// For now no support for marking a single interface by name. We would have to correctly support
// mangled names for generics to do that correctly. Simply mark all interfaces on the type for now.
// Require Interfaces annotation
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
// Interfaces is transitive, so the return values will always have at least Interfaces annotation
DynamicallyAccessedMemberTypes returnMemberTypes = DynamicallyAccessedMemberTypes.Interfaces;
// Propagate All annotation across the call - All is a superset of Interfaces
if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers
&& valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
returnMemberTypes = DynamicallyAccessedMemberTypes.All;
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, returnMemberTypes));
}
}
}
}
break;
//
// AssemblyQualifiedName
//
case IntrinsicId.Type_get_AssemblyQualifiedName: {
if (instanceValue.IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers) {
// Currently we don't need to track the difference between Type and String annotated values
// that only matters when we use them, so Type.GetType is the difference really.
// For diagnostics we actually don't want to track the Type.AssemblyQualifiedName
// as the annotation does not come from that call, but from its input.
AddReturnValue (valueWithDynamicallyAccessedMembers);
} else if (value == NullValue.Instance) {
// NullReferenceException, no return value.
AddReturnValue (MultiValueLattice.Top);
} else {
AddReturnValue (UnknownValue.Instance);
}
}
}
break;
//
// System.Runtime.CompilerServices.RuntimeHelpers
//
// RunClassConstructor (RuntimeTypeHandle type)
//
case IntrinsicId.RuntimeHelpers_RunClassConstructor:
if (argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var typeHandleValue in argumentValues[0].AsEnumerable ()) {
if (typeHandleValue is RuntimeTypeHandleValue runtimeTypeHandleValue) {
MarkStaticConstructor (runtimeTypeHandleValue.RepresentedType);
} else if (typeHandleValue is RuntimeTypeHandleForValueWithDynamicallyAccessedMembers damAnnotatedHandle
&& (damAnnotatedHandle.UnderlyingTypeValue.DynamicallyAccessedMemberTypes & DynamicallyAccessedMemberTypes.NonPublicConstructors) != 0) {
// No action needed, NonPublicConstructors keeps the static constructor on the type
} else {
_diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedTypeInRuntimeHelpersRunClassConstructor, calledMethod.GetDisplayName ());
}
}
break;
//
// GetConstructors (BindingFlags)
// GetMethods (BindingFlags)
// GetFields (BindingFlags)
// GetEvents (BindingFlags)
// GetProperties (BindingFlags)
// GetNestedTypes (BindingFlags)
// GetMembers (BindingFlags)
//
case IntrinsicId.Type_GetConstructors__BindingFlags:
case IntrinsicId.Type_GetMethods__BindingFlags:
case IntrinsicId.Type_GetFields__BindingFlags:
case IntrinsicId.Type_GetProperties__BindingFlags:
case IntrinsicId.Type_GetEvents__BindingFlags:
case IntrinsicId.Type_GetNestedTypes__BindingFlags:
case IntrinsicId.Type_GetMembers__BindingFlags: {
BindingFlags? bindingFlags;
bindingFlags = GetBindingFlagsFromValue (argumentValues[0]);
DynamicallyAccessedMemberTypes memberTypes;
if (BindingFlagsAreUnsupported (bindingFlags)) {
memberTypes = intrinsicId switch {
IntrinsicId.Type_GetConstructors__BindingFlags => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors,
IntrinsicId.Type_GetMethods__BindingFlags => DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods,
IntrinsicId.Type_GetEvents__BindingFlags => DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents,
IntrinsicId.Type_GetFields__BindingFlags => DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields,
IntrinsicId.Type_GetProperties__BindingFlags => DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties,
IntrinsicId.Type_GetNestedTypes__BindingFlags => DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
IntrinsicId.Type_GetMembers__BindingFlags => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
_ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
};
} else {
memberTypes = intrinsicId switch {
IntrinsicId.Type_GetConstructors__BindingFlags => GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags),
IntrinsicId.Type_GetMethods__BindingFlags => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags),
IntrinsicId.Type_GetEvents__BindingFlags => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
IntrinsicId.Type_GetFields__BindingFlags => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
IntrinsicId.Type_GetProperties__BindingFlags => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
IntrinsicId.Type_GetNestedTypes__BindingFlags => GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags),
IntrinsicId.Type_GetMembers__BindingFlags => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags),
_ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
};
}
var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, memberTypes);
_requireDynamicallyAccessedMembersAction.Invoke (instanceValue, targetValue);
}
break;
//
// GetField (string)
// GetField (string, BindingFlags)
// GetEvent (string)
// GetEvent (string, BindingFlags)
// GetProperty (string)
// GetProperty (string, BindingFlags)
// GetProperty (string, Type)
// GetProperty (string, Type[])
// GetProperty (string, Type, Type[])
// GetProperty (string, Type, Type[], ParameterModifier[])
// GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
//
case IntrinsicId.Type_GetField:
case IntrinsicId.Type_GetProperty:
case IntrinsicId.Type_GetEvent: {
if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
BindingFlags? bindingFlags;
if (calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
DynamicallyAccessedMemberTypes memberTypes = intrinsicId switch {
IntrinsicId.Type_GetEvent => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
IntrinsicId.Type_GetField => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
IntrinsicId.Type_GetProperty => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
_ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
};
var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, memberTypes);
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[0].AsEnumerable ()) {
if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
switch (intrinsicId) {
case IntrinsicId.Type_GetEvent:
MarkEventsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
break;
case IntrinsicId.Type_GetField:
MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
break;
case IntrinsicId.Type_GetProperty:
MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
break;
default:
Debug.Fail ("Unreachable.");
break;
}
} else {
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
} else {
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
}
break;
//
// GetMember (String)
// GetMember (String, BindingFlags)
// GetMember (String, MemberTypes, BindingFlags)
//
case IntrinsicId.Type_GetMember: {
if (instanceValue.IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
BindingFlags? bindingFlags;
if (calledMethod.HasMetadataParametersCount (1)) {
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
bindingFlags = BindingFlags.Public | BindingFlags.Instance;
} else if (calledMethod.HasMetadataParametersCount (2) && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
else if (calledMethod.HasMetadataParametersCount (3) && calledMethod.HasParameterOfType ((ParameterIndex) 3, "System.Reflection.BindingFlags")) {
bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
} else // Non recognized intrinsic
throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is an unexpected intrinsic.");
DynamicallyAccessedMemberTypes requiredMemberTypes;
if (BindingFlagsAreUnsupported (bindingFlags)) {
requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
} else {
requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags);
}
var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, requiredMemberTypes);
// Go over all types we've seen
foreach (var value in instanceValue.AsEnumerable ()) {
// Mark based on bitfield requirements
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
break;
//
// GetMethod (string)
// GetMethod (string, BindingFlags)
// GetMethod (string, Type[])
// GetMethod (string, Type[], ParameterModifier[])
// GetMethod (string, BindingFlags, Type[])
// GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
// GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
// GetMethod (string, int, Type[])
// GetMethod (string, int, Type[], ParameterModifier[]?)
// GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
// GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
//
case IntrinsicId.Type_GetMethod: {
if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
BindingFlags? bindingFlags;
if (calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
else if (calledMethod.HasParameterOfType ((ParameterIndex) 3, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags));
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[0].AsEnumerable ()) {
if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
AddReturnValue (MultiValueLattice.Top); ; // Initialize return value (so that it's not autofilled if there are no matching methods)
foreach (var methodValue in ProcessGetMethodByName (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags))
AddReturnValue (methodValue);
} else if (stringParam is NullValue) {
// GetMethod(null) throws - so track empty value set as its result
AddReturnValue (MultiValueLattice.Top);
} else {
// Otherwise fall back to the bitfield requirements
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
AddReturnValue (annotatedMethodReturnValue);
}
}
} else if (value is NullValue) {
// null.GetMethod(...) throws - so track empty value set as its result
AddReturnValue (MultiValueLattice.Top);
} else {
// Otherwise fall back to the bitfield requirements
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
AddReturnValue (annotatedMethodReturnValue);
}
}
}
break;
//
// GetNestedType (string)
// GetNestedType (string, BindingFlags)
//
case IntrinsicId.Type_GetNestedType: {
if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
BindingFlags? bindingFlags;
if (calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags));
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[0].AsEnumerable ()) {
if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
AddReturnValue (MultiValueLattice.Top);
foreach (var nestedTypeValue in GetNestedTypesOnType (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags)) {
MarkType (nestedTypeValue.RepresentedType);
AddReturnValue (nestedTypeValue);
}
} else if (stringParam is NullValue) {
AddReturnValue (MultiValueLattice.Top);
} else {
// Otherwise fall back to the bitfield requirements
_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));
}
}
} else if (value is NullValue) {
// null.GetNestedType(..) throws - so track empty value set
AddReturnValue (MultiValueLattice.Top);
} else {
// Otherwise fall back to the bitfield requirements
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
// 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.
if (value is ValueWithDynamicallyAccessedMembers { DynamicallyAccessedMemberTypes: DynamicallyAccessedMemberTypes.All })
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.All));
else
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, DynamicallyAccessedMemberTypes.None));
}
}
}
break;
//
// System.Reflection.RuntimeReflectionExtensions
//
// static GetRuntimeEvent (this Type type, string name)
// static GetRuntimeField (this Type type, string name)
// static GetRuntimeMethod (this Type type, string name, Type[] parameters)
// static GetRuntimeProperty (this Type type, string name)
//
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent:
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField:
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod:
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty: {
if (argumentValues[0].IsEmpty () || argumentValues[1].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
DynamicallyAccessedMemberTypes requiredMemberTypes = intrinsicId switch {
IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent => DynamicallyAccessedMemberTypes.PublicEvents,
IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField => DynamicallyAccessedMemberTypes.PublicFields,
IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod => DynamicallyAccessedMemberTypes.PublicMethods,
IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty => DynamicallyAccessedMemberTypes.PublicProperties,
_ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
};
var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 1), requiredMemberTypes);
foreach (var value in argumentValues[0].AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[1].AsEnumerable ()) {
if (stringParam is KnownStringValue stringValue) {
switch (intrinsicId) {
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent:
MarkEventsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
break;
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField:
MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
break;
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod:
AddReturnValue (MultiValueLattice.Top); // Initialize return value (so that it's not autofilled if there are no matching methods)
foreach (var methodValue in ProcessGetMethodByName (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags))
AddReturnValue (methodValue);
break;
case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
break;
default:
throw new ArgumentException ($"Error processing reflection call '{calledMethod.GetDisplayName ()}' inside {GetContainingSymbolDisplayName ()}. Unexpected member kind.");
}
} else if (stringParam is NullValue) {
// GetRuntimeMethod(type, null) throws - so track empty value set as its result
AddReturnValue (MultiValueLattice.Top);
} else {
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
AddReturnValue (annotatedMethodReturnValue);
}
}
} else if (value is NullValue) {
// GetRuntimeMethod(null, ...) throws - so track empty value set as its result
AddReturnValue (MultiValueLattice.Top);
} else {
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
AddReturnValue (annotatedMethodReturnValue);
}
}
}
break;
//
// System.Linq.Expressions.Expression
//
// static New (Type)
//
case IntrinsicId.Expression_New: {
var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 0), DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
foreach (var value in argumentValues[0].AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
MarkConstructorsOnType (systemTypeValue.RepresentedType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, parameterCount: null);
} else {
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
}
break;
//
// System.Linq.Expressions.Expression
//
// static Property (Expression, MethodInfo)
//
case IntrinsicId.Expression_Property when calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.MethodInfo"): {
if (argumentValues[1].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var value in argumentValues[1].AsEnumerable ()) {
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.RepresentedMethod))
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,
_annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 1), DynamicallyAccessedMemberTypes.None).GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ());
}
}
break;
//
// System.Linq.Expressions.Expression
//
// static Field (Expression, Type, String)
// static Property (Expression, Type, String)
//
case IntrinsicId.Expression_Field:
case IntrinsicId.Expression_Property: {
DynamicallyAccessedMemberTypes memberTypes = intrinsicId == IntrinsicId.Expression_Property
? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties
: DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields;
if (argumentValues[1].IsEmpty () || argumentValues[2].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 1), memberTypes);
foreach (var value in argumentValues[1].AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[2].AsEnumerable ()) {
if (stringParam is KnownStringValue stringValue) {
BindingFlags bindingFlags = argumentValues[0].AsSingleValue () is NullValue ? BindingFlags.Static : BindingFlags.Default;
if (intrinsicId == 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;
//
// System.Linq.Expressions.Expression
//
// static Call (Type, String, Type[], Expression[])
//
case IntrinsicId.Expression_Call: {
BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
var targetValue = _annotations.GetMethodParameterValue (
new ParameterProxy (calledMethod, (ParameterIndex) 0),
GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags));
// This is true even if we "don't know" - so it's only false if we're sure that there are no type arguments
bool hasTypeArguments = (argumentValues[2].AsSingleValue () as ArrayValue)?.Size.AsConstInt () != 0;
foreach (var value in argumentValues[0].AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[1].AsEnumerable ()) {
if (stringParam is KnownStringValue stringValue) {
foreach (var method in GetMethodsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags)) {
ValidateGenericMethodInstantiation (method.RepresentedMethod, argumentValues[2], calledMethod);
MarkMethod (method.RepresentedMethod);
}
} else {
if (hasTypeArguments) {
// We don't know what method the `MakeGenericMethod` was called on, so we have to assume
// that the method may have requirements which we can't fullfil -> warn.
_diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericMethod, calledMethod.GetDisplayName ());
}
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
} else {
if (hasTypeArguments) {
// We don't know what method the `MakeGenericMethod` was called on, so we have to assume
// that the method may have requirements which we can't fullfil -> warn.
_diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericMethod, calledMethod.GetDisplayName ());
}
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
}
break;
//
// Nullable.GetUnderlyingType(Type)
//
case IntrinsicId.Nullable_GetUnderlyingType:
if (argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var singlevalue in argumentValues[0].AsEnumerable ()) {
AddReturnValue (singlevalue switch {
SystemTypeValue systemType =>
systemType.RepresentedType.IsTypeOf ("System", "Nullable`1")
// This will happen if there's typeof(Nullable<>).MakeGenericType(unknown) - we know the return value is Nullable<>
// but we don't know of what. So we represent it as known type, but not as known nullable type.
// Has to be special cased here, since we need to return "unknown" type.
? annotatedMethodReturnValue
: MultiValueLattice.Top, // This returns null at runtime, so return empty value
NullableSystemTypeValue nullableSystemType => nullableSystemType.UnderlyingTypeValue,
NullableValueWithDynamicallyAccessedMembers nullableDamValue => nullableDamValue.UnderlyingTypeValue,
ValueWithDynamicallyAccessedMembers damValue => damValue,
_ => annotatedMethodReturnValue
});
}
break;
//
// System.Type
//
// GetType (string)
// GetType (string, Boolean)
// GetType (string, Boolean, Boolean)
// GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>)
// GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean)
// GetType (string, Func<AssemblyName, Assembly>, Func<Assembly, String, Boolean, Type>, Boolean, Boolean)
//
case IntrinsicId.Type_GetType: {
if (argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
if ((calledMethod.HasMetadataParametersCount (3) && calledMethod.HasParameterOfType ((ParameterIndex) 2, "System.Boolean") && argumentValues[2].AsConstInt () != 0) ||
(calledMethod.HasMetadataParametersCount (5) && argumentValues[4].AsConstInt () != 0)) {
_diagnosticContext.AddDiagnostic (DiagnosticId.CaseInsensitiveTypeGetTypeCallIsNotSupported, calledMethod.GetDisplayName ());
returnValue = MultiValueLattice.Top; // This effectively disables analysis of anything which uses the return value
break;
}
foreach (var typeNameValue in argumentValues[0].AsEnumerable ()) {
if (typeNameValue is KnownStringValue knownStringValue) {
if (!_requireDynamicallyAccessedMembersAction.TryResolveTypeNameAndMark (knownStringValue.Contents, false, out TypeProxy foundType)) {
// Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back.
AddReturnValue (MultiValueLattice.Top);
} else {
AddReturnValue (new SystemTypeValue (foundType));
}
} else if (typeNameValue == NullValue.Instance) {
// Nothing to do - this throws at runtime
AddReturnValue (MultiValueLattice.Top);
} else if (typeNameValue is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers && valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes != 0) {
// Propagate the annotation from the type name to the return value. Annotation on a string value will be fulfilled whenever a value is assigned to the string with annotation.
// So while we don't know which type it is, we can guarantee that it will fulfill the annotation.
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes));
} else {
_diagnosticContext.AddDiagnostic (DiagnosticId.UnrecognizedTypeNameInTypeGetType, calledMethod.GetDisplayName ());
AddReturnValue (MultiValueLattice.Top);
}
}
}
break;
//
// System.Type
//
// Type MakeGenericType (params Type[] typeArguments)
//
case IntrinsicId.Type_MakeGenericType:
if (instanceValue.IsEmpty () || argumentValues[0].IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is SystemTypeValue typeValue) {
// Special case Nullable<T>
// Nullables without a type argument are considered SystemTypeValues
if (typeValue.RepresentedType.IsTypeOf ("System", "Nullable`1")) {
// Note that we're not performing any generic parameter validation
// Special case: Nullable<T> where T : struct
// The struct constraint in C# implies new() constraint, but Nullable doesn't make a use of that part.
// There are several places even in the framework where typeof(Nullable<>).MakeGenericType would warn
// without any good reason to do so.
foreach (var argumentValue in argumentValues[0].AsEnumerable ()) {
if ((argumentValue as ArrayValue)?.TryGetValueByIndex (0, out var underlyingMultiValue) == true) {
foreach (var underlyingValue in underlyingMultiValue.AsEnumerable ()) {
switch (underlyingValue) {
// Don't warn on these types - it will throw instead
case NullableValueWithDynamicallyAccessedMembers:
case NullableSystemTypeValue:
case SystemTypeValue maybeArrayValue when maybeArrayValue.RepresentedType.IsTypeOf ("System", "Array"):
AddReturnValue (MultiValueLattice.Top);
break;
case SystemTypeValue systemTypeValue:
AddReturnValue (new NullableSystemTypeValue (typeValue.RepresentedType, new SystemTypeValue (systemTypeValue.RepresentedType)));
break;
// Generic Parameters and method parameters with annotations
case ValueWithDynamicallyAccessedMembers damValue:
AddReturnValue (new NullableValueWithDynamicallyAccessedMembers (typeValue.RepresentedType, damValue));
break;
// Everything else assume it has no annotations
default:
// This returns just Nullable<> SystemTypeValue - so some things will work, but GetUnderlyingType won't propagate anything
// It's special cased to do that.
AddReturnValue (value);
break;
}
}
} else {
// This returns just Nullable<> SystemTypeValue - so some things will work, but GetUnderlyingType won't propagate anything
// It's special cased to do that.
AddReturnValue (value);
}
}
// We want to skip adding the `value` to the return Value because we have already added Nullable<value>
continue;
} else {
// Any other type - perform generic parameter validation
var genericParameterValues = GetGenericParameterValues (typeValue.RepresentedType.GetGenericParameters ());
if (!AnalyzeGenericInstantiationTypeArray (argumentValues[0], calledMethod, genericParameterValues)) {
_diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericType, calledMethod.GetDisplayName ());
}
}
} else if (value == NullValue.Instance) {
// At runtime this would throw - so it has no effect on analysis
AddReturnValue (MultiValueLattice.Top);
} else {
// We have no way to "include more" to fix this if we don't know, so we have to warn
_diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericType, calledMethod.GetDisplayName ());
}
// We don't want to lose track of the type
// in case this is e.g. Activator.CreateInstance(typeof(Foo<>).MakeGenericType(...));
// Note this is not called in the Nullable case - we skipt this via the 'continue'.
AddReturnValue (value);
}
break;
//
// Type.BaseType
//
case IntrinsicId.Type_get_BaseType: {
if (instanceValue.IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers) {
DynamicallyAccessedMemberTypes propagatedMemberTypes = DynamicallyAccessedMemberTypes.None;
if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes == DynamicallyAccessedMemberTypes.All)
propagatedMemberTypes = DynamicallyAccessedMemberTypes.All;
else {
// PublicConstructors are not propagated to base type
if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicEvents))
propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicEvents;
if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicFields))
propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicFields;
if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicMethods))
propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicMethods;
// PublicNestedTypes are not propagated to base type
// PublicParameterlessConstructor is not propagated to base type
if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicProperties))
propagatedMemberTypes |= DynamicallyAccessedMemberTypes.PublicProperties;
if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.Interfaces))
propagatedMemberTypes |= DynamicallyAccessedMemberTypes.Interfaces;
}
AddReturnValue (_annotations.GetMethodReturnValue (calledMethod, _isNewObj, propagatedMemberTypes));
} else if (value is SystemTypeValue systemTypeValue) {
if (TryGetBaseType (systemTypeValue.RepresentedType, out var baseType))
AddReturnValue (new SystemTypeValue (baseType.Value));
else
AddReturnValue (annotatedMethodReturnValue);
} else if (value == NullValue.Instance) {
// Ignore nulls - null.BaseType will fail at runtime, but it has no effect on static analysis
AddReturnValue (MultiValueLattice.Top);
continue;
} else {
// Unknown input - propagate a return value without any annotation - we know it's a Type but we know nothing about it
AddReturnValue (annotatedMethodReturnValue);
}
}
}
break;
//
// GetConstructor (Type[])
// GetConstructor (BindingFlags, Type[])
// GetConstructor (BindingFlags, Binder, Type[], ParameterModifier [])
// GetConstructor (BindingFlags, Binder, CallingConventions, Type[], ParameterModifier [])
//
case IntrinsicId.Type_GetConstructor: {
if (instanceValue.IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
BindingFlags? bindingFlags;
if (calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Reflection.BindingFlags"))
bindingFlags = GetBindingFlagsFromValue (argumentValues[0]);
else
// Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
bindingFlags = BindingFlags.Public | BindingFlags.Instance;
int? ctorParameterCount = calledMethod.GetMetadataParametersCount () switch {
1 => (argumentValues[0].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
2 => (argumentValues[1].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
4 => (argumentValues[2].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
5 => (argumentValues[3].AsSingleValue () as ArrayValue)?.Size.AsConstInt (),
_ => null,
};
// Go over all types we've seen
foreach (var value in instanceValue.AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue && !BindingFlagsAreUnsupported (bindingFlags)) {
if (HasBindingFlag (bindingFlags, BindingFlags.Public) && !HasBindingFlag (bindingFlags, BindingFlags.NonPublic)
&& ctorParameterCount == 0) {
MarkPublicParameterlessConstructorOnType (systemTypeValue.RepresentedType);
} else {
MarkConstructorsOnType (systemTypeValue.RepresentedType, bindingFlags, parameterCount: null);
}
} else {
// Otherwise fall back to the bitfield requirements
var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags);
// We can scope down the public constructors requirement if we know the number of parameters is 0
if (requiredMemberTypes == DynamicallyAccessedMemberTypes.PublicConstructors && ctorParameterCount == 0)
requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
var targetValue = _annotations.GetMethodThisParameterValue (calledMethod, requiredMemberTypes);
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
}
break;
//
// System.Reflection.MethodInfo
//
// MakeGenericMethod (Type[] typeArguments)
//
case IntrinsicId.MethodInfo_MakeGenericMethod: {
if (instanceValue.IsEmpty ()) {
returnValue = MultiValueLattice.Top;
break;
}
foreach (var methodValue in instanceValue.AsEnumerable ()) {
if (methodValue is SystemReflectionMethodBaseValue methodBaseValue) {
ValidateGenericMethodInstantiation (methodBaseValue.RepresentedMethod, argumentValues[0], calledMethod);
} else if (methodValue == NullValue.Instance) {
// Nothing to do
} else {
// We don't know what method the `MakeGenericMethod` was called on, so we have to assume
// that the method may have requirements which we can't fullfil -> warn.
_diagnosticContext.AddDiagnostic (DiagnosticId.MakeGenericMethod, calledMethod.GetDisplayName ());
}
}
// MakeGenericMethod doesn't change the identity of the MethodBase we're tracking so propagate to the return value
AddReturnValue (instanceValue);
}
break;
//
// System.Activator
//
// static CreateInstance (System.Type type)
// static CreateInstance (System.Type type, bool nonPublic)
// static CreateInstance (System.Type type, params object?[]? args)
// static CreateInstance (System.Type type, object?[]? args, object?[]? activationAttributes)
// static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture)
// static CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes) { throw null; }
//
case IntrinsicId.Activator_CreateInstance__Type: {
int? ctorParameterCount = null;
BindingFlags bindingFlags = BindingFlags.Instance;
if (calledMethod.GetMetadataParametersCount () > 1) {
if (calledMethod.HasParameterOfType ((ParameterIndex) 1, "System.Boolean")) {
// The overload that takes a "nonPublic" bool
bool nonPublic = argumentValues[1].AsConstInt () != 0;
if (nonPublic)
bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
else
bindingFlags |= BindingFlags.Public;
ctorParameterCount = 0;
} else {
// Overload that has the parameters as the second or fourth argument
int argsParam = calledMethod.HasMetadataParametersCount (2) || calledMethod.HasMetadataParametersCount (3) ? 1 : 3;
if (argumentValues.Count > argsParam) {
if (argumentValues[argsParam].AsSingleValue () is ArrayValue arrayValue &&
arrayValue.Size.AsConstInt () != null)
ctorParameterCount = arrayValue.Size.AsConstInt ();
else if (argumentValues[argsParam].AsSingleValue () is NullValue)
ctorParameterCount = 0;
}
if (calledMethod.GetMetadataParametersCount () > 3) {
if (argumentValues[1].AsConstInt () is int constInt)
bindingFlags |= (BindingFlags) constInt;
else
bindingFlags |= BindingFlags.NonPublic | BindingFlags.Public;
} else {
bindingFlags |= BindingFlags.Public;
}
}
} else {
// The overload with a single System.Type argument
ctorParameterCount = 0;
bindingFlags |= BindingFlags.Public;
}
// Go over all types we've seen
foreach (var value in argumentValues[0].AsEnumerable ()) {
if (value is SystemTypeValue systemTypeValue) {
// Special case known type values as we can do better by applying exact binding flags and parameter count.
MarkConstructorsOnType (systemTypeValue.RepresentedType, bindingFlags, ctorParameterCount);
} else {
// Otherwise fall back to the bitfield requirements
var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags);
// Special case the public parameterless constructor if we know that there are 0 args passed in
if (ctorParameterCount == 0 && requiredMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors)) {
requiredMemberTypes &= ~DynamicallyAccessedMemberTypes.PublicConstructors;
requiredMemberTypes |= DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
}
var targetValue = _annotations.GetMethodParameterValue (new (calledMethod, (ParameterIndex) 0), requiredMemberTypes);
_requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
}
}
break;
//
// System.Activator
//
// static CreateInstance (string assemblyName, string typeName)
// static CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object?[]? args, System.Globalization.CultureInfo? culture, object?[]? activationAttributes)
// static CreateInstance (string assemblyName, string typeName, object?[]? activationAttributes)
//
case IntrinsicId.Activator_CreateInstance__AssemblyName_TypeName:
ProcessCreateInstanceByName (calledMethod, argumentValues);
break;
//
// System.Activator
//
// static CreateInstanceFrom (string assemblyFile, string typeName)
// static CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// static CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
//
case IntrinsicId.Activator_CreateInstanceFrom:
ProcessCreateInstanceByName (calledMethod, argumentValues);
break;
//
// System.AppDomain
//
// CreateInstance (string assemblyName, string typeName)
// CreateInstance (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// CreateInstance (string assemblyName, string typeName, object? []? activationAttributes)
//
// CreateInstanceAndUnwrap (string assemblyName, string typeName)
// CreateInstanceAndUnwrap (string assemblyName, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// CreateInstanceAndUnwrap (string assemblyName, string typeName, object? []? activationAttributes)
//
// CreateInstanceFrom (string assemblyFile, string typeName)
// CreateInstanceFrom (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// CreateInstanceFrom (string assemblyFile, string typeName, object? []? activationAttributes)
//
// CreateInstanceFromAndUnwrap (string assemblyFile, string typeName)
// CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, bool ignoreCase, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder? binder, object? []? args, System.Globalization.CultureInfo? culture, object? []? activationAttributes)
// CreateInstanceFromAndUnwrap (string assemblyFile, string typeName, object? []? activationAttributes)
//
case IntrinsicId.AppDomain_CreateInstance:
case IntrinsicId.AppDomain_CreateInstanceAndUnwrap:
case IntrinsicId.AppDomain_CreateInstanceFrom:
case IntrinsicId.AppDomain_CreateInstanceFromAndUnwrap:
ProcessCreateInstanceByName (calledMethod, argumentValues);
break;
//
// System.Reflection.Assembly
//
// CreateInstance (string typeName)
// CreateInstance (string typeName, bool ignoreCase)
// CreateInstance (string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder? binder, object []? args, CultureInfo? culture, object []? activationAttributes)
//
case IntrinsicId.Assembly_CreateInstance:
// For now always fail since we don't track assemblies (dotnet/linker/issues/1947)
_diagnosticContext.AddDiagnostic (DiagnosticId.ParametersOfAssemblyCreateInstanceCannotBeAnalyzed, calledMethod.GetDisplayName ());
break;
case IntrinsicId.None:
// Verify the argument values match the annotations on the parameter definition
if (requiresDataFlowAnalysis) {
foreach (var parameter in calledMethod.GetParameters ()) {
if (parameter.GetReferenceKind () is ReferenceKind.Out)
continue;
if (parameter.IsImplicitThis) {
_requireDynamicallyAccessedMembersAction.Invoke (instanceValue, _annotations.GetMethodThisParameterValue (calledMethod));
continue;
}
_requireDynamicallyAccessedMembersAction.Invoke (argumentValues[parameter.MetadataIndex], _annotations.GetMethodParameterValue (parameter));
}
}
break;
default:
return false;
}
if (MethodIsTypeConstructor (calledMethod))
returnValue = UnknownValue.Instance;
methodReturnValue = returnValue;
return true;
void AddReturnValue (MultiValue value)
{
returnValue = (returnValue == null) ? value : MultiValueLattice.Meet (returnValue.Value, value);
}
}