diff --git a/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs b/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs index 81403cc4fc43..9c42d01e74b2 100644 --- a/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs +++ b/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs @@ -140,15 +140,15 @@ internal sealed class MultiDimArrayTypeName : HasElementTypeName public MultiDimArrayTypeName(TypeName elementTypeName, int rank) : base(elementTypeName) { - _rank = rank; + Rank = rank; } public sealed override string ToString() { - return ElementTypeName + "[" + (_rank == 1 ? "*" : new string(',', _rank - 1)) + "]"; + return ElementTypeName + "[" + (Rank == 1 ? "*" : new string(',', Rank - 1)) + "]"; } - private int _rank; + public int Rank { get; } } // diff --git a/src/linker/Linker.Dataflow/MethodBodyScanner.cs b/src/linker/Linker.Dataflow/MethodBodyScanner.cs index 538e8937e148..38217515aaea 100644 --- a/src/linker/Linker.Dataflow/MethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/MethodBodyScanner.cs @@ -714,7 +714,7 @@ private void ScanLdtoken ( } if (operation.Operand is TypeReference typeReference) { - var resolvedReference = typeReference.Resolve (); + var resolvedReference = typeReference.ResolveToMainTypeDefinition (); if (resolvedReference != null) { StackSlot slot = new StackSlot (new RuntimeTypeHandleValue (resolvedReference)); currentStack.Push (slot); diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index e493748e7158..e21f0c7a85d3 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -109,11 +109,11 @@ public void ProcessAttributeDataflow (FieldDefinition field, CustomAttributeArgu } } - ValueNode GetValueNodeForCustomAttributeArgument (CustomAttributeArgument argument) + static ValueNode GetValueNodeForCustomAttributeArgument (CustomAttributeArgument argument) { ValueNode valueNode; if (argument.Type.Name == "Type") { - TypeDefinition referencedType = ((TypeReference) argument.Value).Resolve (); + TypeDefinition referencedType = ((TypeReference) argument.Value).ResolveToMainTypeDefinition (); valueNode = referencedType == null ? null : new SystemTypeValue (referencedType); } else if (argument.Type.MetadataType == MetadataType.String) { valueNode = new KnownStringValue ((string) argument.Value); @@ -130,7 +130,7 @@ public void ProcessGenericArgumentDataFlow (GenericParameter genericParameter, T var annotation = _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameter); Debug.Assert (annotation != DynamicallyAccessedMemberTypes.None); - ValueNode valueNode = GetValueNodeFromGenericArgument (genericArgument); + ValueNode valueNode = GetTypeValueNodeFromGenericArgument (genericArgument); bool enableReflectionPatternReporting = !(source is MethodDefinition sourceMethod) || ShouldEnableReflectionPatternReporting (sourceMethod); var reflectionContext = new ReflectionPatternContext (_context, enableReflectionPatternReporting, source, genericParameter); @@ -138,14 +138,14 @@ public void ProcessGenericArgumentDataFlow (GenericParameter genericParameter, T RequireDynamicallyAccessedMembers (ref reflectionContext, annotation, valueNode, genericParameter); } - ValueNode GetValueNodeFromGenericArgument (TypeReference genericArgument) + ValueNode GetTypeValueNodeFromGenericArgument (TypeReference genericArgument) { if (genericArgument is GenericParameter inputGenericParameter) { // Technically this should be a new value node type as it's not a System.Type instance representation, but just the generic parameter // That said we only use it to perform the dynamically accessed members checks and for that purpose treating it as System.Type is perfectly valid. return new SystemTypeForGenericParameterValue (inputGenericParameter, _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (inputGenericParameter)); } else { - TypeDefinition genericArgumentTypeDef = genericArgument.Resolve (); + TypeDefinition genericArgumentTypeDef = genericArgument.ResolveToMainTypeDefinition (); if (genericArgumentTypeDef != null) { return new SystemTypeValue (genericArgumentTypeDef); } else { @@ -752,13 +752,13 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c if (methodParam.ParameterIndex == 0) { staticType = callingMethodDefinition.DeclaringType; } else { - staticType = callingMethodDefinition.Parameters[methodParam.ParameterIndex - 1].ParameterType.Resolve (); + staticType = callingMethodDefinition.Parameters[methodParam.ParameterIndex - 1].ParameterType.ResolveToMainTypeDefinition (); } } else { - staticType = callingMethodDefinition.Parameters[methodParam.ParameterIndex].ParameterType.Resolve (); + staticType = callingMethodDefinition.Parameters[methodParam.ParameterIndex].ParameterType.ResolveToMainTypeDefinition (); } } else if (methodParams[0] is LoadFieldValue loadedField) { - staticType = loadedField.Field.FieldType.Resolve (); + staticType = loadedField.Field.FieldType.ResolveToMainTypeDefinition (); } if (staticType != null) { @@ -802,7 +802,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c foreach (var typeNameValue in methodParams[0].UniqueValues ()) { if (typeNameValue is KnownStringValue knownStringValue) { TypeReference foundTypeRef = _context.TypeNameResolver.ResolveTypeName (knownStringValue.Contents); - TypeDefinition foundType = foundTypeRef?.Resolve (); + TypeDefinition foundType = foundTypeRef?.ResolveToMainTypeDefinition (); if (foundType == null) { // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back. reflectionContext.RecordHandledPattern (); @@ -850,7 +850,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c // Go over all types we've seen foreach (var value in methodParams[0].UniqueValues ()) { if (value is SystemTypeValue systemTypeValue) { - MarkConstructorsOnType (ref reflectionContext, systemTypeValue.TypeRepresented, (Func) null, bindingFlags); + MarkConstructorsOnType (ref reflectionContext, systemTypeValue.TypeRepresented, null, bindingFlags); reflectionContext.RecordHandledPattern (); } else { // Otherwise fall back to the bitfield requirements @@ -987,10 +987,10 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c // GetProperty (string, Type, Type[], ParameterModifier[]) // GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[]) // - case var fieldPropertyOrEvent when ((fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent) + case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent) && calledMethod.DeclaringType.Namespace == "System" && calledMethod.DeclaringType.Name == "Type" - && calledMethod.Parameters[0].ParameterType.FullName == "System.String") + && calledMethod.Parameters[0].ParameterType.FullName == "System.String" && calledMethod.HasThis: { reflectionContext.AnalyzingPattern (); @@ -1161,7 +1161,7 @@ methodParams[argsParam] is ArrayValue arrayValue && RequireDynamicallyAccessedMembers ( ref reflectionContext, DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, - GetValueNodeFromGenericArgument (genericCalledMethod.GenericArguments[0]), + GetTypeValueNodeFromGenericArgument (genericCalledMethod.GenericArguments[0]), calledMethodDefinition.GenericParameters[0]); } break; @@ -1340,11 +1340,13 @@ void ProcessCreateInstanceByName (ref ReflectionPatternContext reflectionContext continue; } - var resolvedType = (_context.TypeNameResolver.ResolveTypeName (resolvedAssembly, typeNameStringValue.Contents))?.Resolve (); - if (resolvedType == null) { + var typeRef = _context.TypeNameResolver.ResolveTypeName (resolvedAssembly, typeNameStringValue.Contents); + var resolvedType = typeRef?.Resolve (); + if (resolvedType == null || typeRef is ArrayType) { // It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case // Note that we did find the assembly, so it's not a linker config problem, it's either intentional, or wrong versions of assemblies - // but linker can't know that. + // but linker can't know that. In case a user tries to create an array using System.Activator we should simply ignore it, the user + // might expect an exception to be thrown. reflectionContext.RecordHandledPattern (); continue; } @@ -1376,28 +1378,28 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2067, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method)}' " + $"don't match those on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (ParameterDefinition sourceParameter, MethodReturnType targetMethodReturnType): reflectionContext.RecordUnrecognizedPattern ( 2068, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method)}' " + $"don't match those on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (ParameterDefinition sourceParameter, FieldDefinition targetField): reflectionContext.RecordUnrecognizedPattern ( 2069, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method)}' " + $"don't match those on the field '{targetField.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (ParameterDefinition sourceParameter, MethodDefinition targetMethod): reflectionContext.RecordUnrecognizedPattern ( 2070, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method)}' " + $"don't match those on the implicit 'this' parameter of method '{targetMethod.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (ParameterDefinition sourceParameter, GenericParameter targetGenericParameter): // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used @@ -1405,7 +1407,7 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2071, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (sourceParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceParameter.Method)}' " + $"don't match those on the generic parameter '{targetGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodReturnType sourceMethodReturnType, ParameterDefinition targetParameter): @@ -1413,28 +1415,28 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2072, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method)}' " + $"don't match those on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodReturnType sourceMethodReturnType, MethodReturnType targetMethodReturnType): reflectionContext.RecordUnrecognizedPattern ( 2073, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method)}' " + $"don't match those on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodReturnType sourceMethodReturnType, FieldDefinition targetField): reflectionContext.RecordUnrecognizedPattern ( 2074, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method)}' " + $"don't match those on the field '{targetField.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodReturnType sourceMethodReturnType, MethodDefinition targetMethod): reflectionContext.RecordUnrecognizedPattern ( 2075, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method)}' " + $"don't match those on the implicit 'this' parameter of method '{targetMethod.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodReturnType sourceMethodReturnType, GenericParameter targetGenericParameter): // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used @@ -1442,7 +1444,7 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2076, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (sourceMethodReturnType.Method)}' " + $"don't match those on the generic parameter '{targetGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (FieldDefinition sourceField, ParameterDefinition targetParameter): @@ -1450,28 +1452,28 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2077, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '{sourceField.GetDisplayName ()}' " + $"don't match those on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (FieldDefinition sourceField, MethodReturnType targetMethodReturnType): reflectionContext.RecordUnrecognizedPattern ( 2078, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '{sourceField.GetDisplayName ()}' " + $"don't match those on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (FieldDefinition sourceField, FieldDefinition targetField): reflectionContext.RecordUnrecognizedPattern ( 2079, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '{sourceField.GetDisplayName ()}' " + $"don't match those on the field '{targetField.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (FieldDefinition sourceField, MethodDefinition targetMethod): reflectionContext.RecordUnrecognizedPattern ( 2080, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '{sourceField.GetDisplayName ()}' " + $"don't match those on the implicit 'this' parameter of method '{targetMethod.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (FieldDefinition sourceField, GenericParameter targetGenericParameter): // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used @@ -1479,7 +1481,7 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2081, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '{sourceField.GetDisplayName ()}' " + $"don't match those on the generic parameter '{targetGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodDefinition sourceMethod, ParameterDefinition targetParameter): @@ -1487,28 +1489,28 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2082, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{sourceMethod.GetDisplayName ()}' " + $"don't match those on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodDefinition sourceMethod, MethodReturnType targetMethodReturnType): reflectionContext.RecordUnrecognizedPattern ( 2083, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{sourceMethod.GetDisplayName ()}' " + $"don't match those on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodDefinition sourceMethod, FieldDefinition targetField): reflectionContext.RecordUnrecognizedPattern ( 2084, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{sourceMethod.GetDisplayName ()}' " + $"don't match those on the field '{targetField.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodDefinition sourceMethod, MethodDefinition targetMethod): reflectionContext.RecordUnrecognizedPattern ( 2085, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{sourceMethod.GetDisplayName ()}' " + $"don't match those on the implicit 'this' parameter of method '{targetMethod.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (MethodDefinition sourceMethod, GenericParameter targetGenericParameter): // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used @@ -1516,7 +1518,7 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2086, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{sourceMethod.GetDisplayName ()}' " + $"don't match those on the generic parameter '{targetGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (GenericParameter sourceGenericParameter, ParameterDefinition targetParameter): @@ -1524,21 +1526,21 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2087, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter '{sourceGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter)}' " + $"don't match those on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (targetParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetParameter.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (GenericParameter sourceGenericParameter, MethodReturnType targetMethodReturnType): reflectionContext.RecordUnrecognizedPattern ( 2088, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter '{sourceGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter)}' " + $"don't match those on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (targetMethodReturnType.Method)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (GenericParameter sourceGenericParameter, FieldDefinition targetField): reflectionContext.RecordUnrecognizedPattern ( 2089, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter '{sourceGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter)}' " + $"don't match those on the field '{targetField.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (GenericParameter sourceGenericParameter, MethodDefinition targetMethod): // Currently this is never generated, it might be possible one day if we try to validate annotations on results of reflection @@ -1552,14 +1554,14 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC 2090, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter '{sourceGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter)}' " + $"don't match those on the implicit 'this' parameter of method '{targetMethod.GetDisplayName ()}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; case (GenericParameter sourceGenericParameter, GenericParameter targetGenericParameter): reflectionContext.RecordUnrecognizedPattern ( 2091, $"The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter '{sourceGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (sourceGenericParameter)}' " + $"don't match those on the generic parameter '{targetGenericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (targetGenericParameter)}'. " + - $"The source value must declare at least the same requirements as those declared on the target location it's assigned to "); + $"The source value must declare at least the same requirements as those declared on the target location it's assigned to"); break; default: @@ -1571,11 +1573,13 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC } else if (uniqueValue is SystemTypeValue systemTypeValue) { MarkTypeForDynamicallyAccessedMembers (ref reflectionContext, systemTypeValue.TypeRepresented, requiredMemberTypes); } else if (uniqueValue is KnownStringValue knownStringValue) { - TypeDefinition foundType = _context.TypeNameResolver.ResolveTypeName (knownStringValue.Contents)?.Resolve (); + TypeReference typeRef = _context.TypeNameResolver.ResolveTypeName (knownStringValue.Contents); + TypeDefinition foundType = typeRef?.ResolveToMainTypeDefinition (); if (foundType == null) { // Intentionally ignore - it's not wrong for code to call Type.GetType on non-existing name, the code might expect null/exception back. reflectionContext.RecordHandledPattern (); } else { + MarkType (ref reflectionContext, typeRef); MarkTypeForDynamicallyAccessedMembers (ref reflectionContext, foundType, requiredMemberTypes); } } else if (uniqueValue == NullValue.Instance) { @@ -1617,7 +1621,7 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC reflectionContext.RecordHandledPattern (); } - bool BindingFlagsAreSupported (BindingFlags bindingFlags) + static bool BindingFlagsAreSupported (BindingFlags bindingFlags) { return (bindingFlags & BindingFlags.IgnoreCase) == BindingFlags.IgnoreCase || (int) bindingFlags > 255; } @@ -1649,6 +1653,12 @@ void MarkTypeForDynamicallyAccessedMembers (ref ReflectionPatternContext reflect } } + void MarkType (ref ReflectionPatternContext reflectionContext, TypeReference typeReference) + { + var source = reflectionContext.Source; + reflectionContext.RecordRecognizedPattern (typeReference?.Resolve (), () => _markStep.MarkTypeVisibleToReflection (typeReference, new DependencyInfo (DependencyKind.AccessedViaReflection, source), source)); + } + void MarkMethod (ref ReflectionPatternContext reflectionContext, MethodDefinition method) { var source = reflectionContext.Source; diff --git a/src/linker/Linker/TypeNameResolver.cs b/src/linker/Linker/TypeNameResolver.cs index 379d8708d48d..8e4fc9911bd9 100644 --- a/src/linker/Linker/TypeNameResolver.cs +++ b/src/linker/Linker/TypeNameResolver.cs @@ -77,7 +77,14 @@ TypeReference ResolveTypeName (AssemblyDefinition assembly, TypeName typeName) if (elementType == null) return null; - return elementType; + return typeName switch + { + ArrayTypeName _ => new ArrayType (elementType), + MultiDimArrayTypeName multiDimArrayTypeName => new ArrayType (elementType, multiDimArrayTypeName.Rank), + ByRefTypeName _ => new ByReferenceType (elementType), + PointerTypeName _ => new PointerType (elementType), + _ => elementType + }; } return assembly.MainModule.GetType (typeName.ToString ()); diff --git a/src/linker/Linker/TypeReferenceExtensions.cs b/src/linker/Linker/TypeReferenceExtensions.cs index cddf27c89b77..ba028933376d 100644 --- a/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/linker/Linker/TypeReferenceExtensions.cs @@ -375,5 +375,17 @@ public static bool IsSubclassOf (this TypeReference type, string ns, string name return false; } + + // Array types that are dynamically accessed should resolve to System.Array instead of its element type - which is what Cecil resolves to. + // Any data flow annotations placed on a type parameter which receives an array type apply to the array itself. None of the members in its + // element type should be marked. + public static TypeDefinition ResolveToMainTypeDefinition (this TypeReference type) + { + return type switch + { + ArrayType _ => type.Module.ImportReference (typeof (Array))?.Resolve (), + _ => type?.Resolve () + }; + } } } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs index b021f582bd7a..a33645c533ea 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs @@ -128,9 +128,7 @@ private static void RequireCombinationOnString ( { } - // Issue: https://github.com/mono/linker/issues/1537 - //[Kept] - //[KeptMember (".ctor()")] + [Kept] class FromStringConstantWithGenericInner { } @@ -143,10 +141,57 @@ class FromStringConstantWithGeneric public T GetValue () { return default (T); } } + [Kept] + class FromStringConstantWithGenericInnerInner + { + [Kept] + public void Method () + { + } + + int unusedField; + } + + [Kept] + class FromStringConstantWithGenericInnerOne< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + T> + { + } + + [Kept] + class FromStringConstantWithGenericInnerTwo + { + void UnusedMethod () + { + } + } + + [Kept] + class FromStringConstantWitGenericInnerMultiDimArray + { + } + + [Kept] + class FromStringConstantWithMultiDimArray + { + public void UnusedMethod () { } + } + + [Kept] + [KeptMember (".ctor()")] + class FromStringConstantWithGenericTwoParameters + { + } + [Kept] static void TestFromStringConstantWithGeneric () { RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGeneric`1[[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInner]]"); + RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericTwoParameters`2[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerOne`1[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerInner],Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInnerTwo]"); + RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGeneric`1[[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWitGenericInnerMultiDimArray[,]]]"); + RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithMultiDimArray[,]"); } [Kept] diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs new file mode 100644 index 000000000000..85fa2e11e8f8 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DataFlow/ComplexTypeHandling.cs @@ -0,0 +1,193 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; + +namespace Mono.Linker.Tests.Cases.DataFlow +{ + public class ComplexTypeHandling + { + public static void Main () + { + TestArray (); + TestArrayOnGeneric (); + TestGenericArray (); + TestGenericArrayOnGeneric (); + TestArrayGetTypeFromMethodParam (); + TestArrayGetTypeFromField (); + TestArrayTypeGetType (); + TestArrayCreateInstanceByName (); + TestArrayInAttributeParameter (); + } + + [Kept] + class ArrayElementType + { + public ArrayElementType () { } + + public void PublicMethod () { } + + private int _privateField; + } + + [Kept] + static void TestArray () + { + RequirePublicMethods (typeof (ArrayElementType[])); + } + + [Kept] + static void TestGenericArray () + { + RequirePublicMethodsOnArrayOfGeneric (); + } + + [Kept] + static void RequirePublicMethodsOnArrayOfGeneric () + { + RequirePublicMethods (typeof (T[])); + } + + [Kept] + class ArrayElementInGenericType + { + public ArrayElementInGenericType () { } + + public void PublicMethod () { } + + private int _privateField; + } + + [Kept] + [KeptMember (".ctor()")] + class RequirePublicMethodsGeneric< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + T> + { + } + + [Kept] + static void TestArrayOnGeneric () + { + _ = new RequirePublicMethodsGeneric (); + } + + [Kept] + static void TestGenericArrayOnGeneric () + { + RequirePublicMethodsOnArrayOfGenericParameter (); + } + + [Kept] + static void RequirePublicMethodsOnArrayOfGenericParameter () + { + _ = new RequirePublicMethodsGeneric (); + } + + [Kept] + sealed class ArrayGetTypeFromMethodParamElement + { + // This method should not be marked, instead Array.* should be marked + public void PublicMethod () { } + } + + [Kept] + static void TestArrayGetTypeFromMethodParamHelper (ArrayGetTypeFromMethodParamElement[] p) + { + RequirePublicMethods (p.GetType ()); + } + + [Kept] + static void TestArrayGetTypeFromMethodParam () + { + TestArrayGetTypeFromMethodParamHelper (null); + } + + [Kept] + sealed class ArrayGetTypeFromFieldElement + { + // This method should not be marked, instead Array.* should be marked + public void PublicMethod () { } + } + + [Kept] + static ArrayGetTypeFromFieldElement[] _arrayGetTypeFromField; + + [Kept] + static void TestArrayGetTypeFromField () + { + RequirePublicMethods (_arrayGetTypeFromField.GetType ()); + } + + [Kept] + sealed class ArrayTypeGetTypeElement + { + // This method should not be marked, instead Array.* should be marked + public void PublicMethod () { } + } + + [Kept] + static void TestArrayTypeGetType () + { + RequirePublicMethods (Type.GetType ("Mono.Linker.Tests.Cases.DataFlow.ComplexTypeHandling+ArrayTypeGetTypeElement[]")); + } + + // Nothing should be marked as CreateInstance doesn't work on arrays + class ArrayCreateInstanceByNameElement + { + public ArrayCreateInstanceByNameElement () + { + } + } + + [Kept] + static void TestArrayCreateInstanceByName () + { + Activator.CreateInstance ("test", "Mono.Linker.Tests.Cases.DataFlow.ComplexTypeHandling+ArrayCreateInstanceByNameElement[]"); + } + + [Kept] + class ArrayInAttributeParamElement + { + // This method should not be marked, instead Array.* should be marked + public void PublicMethod () { } + } + + [Kept] + [KeptAttributeAttribute (typeof (RequiresPublicMethodAttribute))] + [RequiresPublicMethod (typeof (ArrayInAttributeParamElement[]))] + static void TestArrayInAttributeParameter () + { + } + + + [Kept] + private static void RequirePublicMethods ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + [KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute))] + Type type) + { + } + + [Kept] + [KeptBaseType (typeof (Attribute))] + class RequiresPublicMethodAttribute : Attribute + { + [Kept] + public RequiresPublicMethodAttribute ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + [KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute))] + Type t) + { + } + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs index f4d45f25458e..9cf5919619ea 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs @@ -17,6 +17,7 @@ public static void Main () TestNullName (); TestEmptyName (); TestNonExistingName (); + TestPropertyOfArray (); TestNullType (); TestDataFlowType (); TestIfElse (1); @@ -82,6 +83,16 @@ static void TestNonExistingName () var property = typeof (PropertyUsedViaReflection).GetProperty ("NonExisting"); } + [Kept] + [RecognizedReflectionAccessPattern ( + typeof (Type), nameof (Type.GetProperty), new Type[] { typeof (string) }, + typeof (Array), nameof (Array.LongLength))] + static void TestPropertyOfArray () + { + var property = typeof (int[]).GetProperty ("LongLength"); + property.GetValue (null); + } + [Kept] static void TestNullType () {