From 2b04c065c84aa8f30600e3b1989c537fc77de95b Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 13 Aug 2020 03:29:44 -0700 Subject: [PATCH] Warnings cleanup (#1385) The most important change is to make warning codes and messages unique - that is for each code there's exactly one message. This means adding quite a few new codes as we were sharing them rather heavily. We also try to avoid logic when constructing messages (to allow for better localization), so instead of having smaller pieces concatenated we introduce several similar warnings. This change also adds more tests for some of the warnings. Infra changes: * Add the warning code parameter to unrecognized reflection call on the interface * Add a new ExpectedWarning test attribute which validates the code, the location and optionally parts of the message * Improved the unrecognized reflection pattern attribute to accept only parts of the message (and to accept more than one) * Add the ability to validat the warning code for unrecognised reflection patterns * Refactor source context for annotated values Makes the source context required by making it a a .ctor argument for all annotated nodes. Make it IMetadataTokenProvider. Fixes the problem with AnnotatedStringValue which was reported as "unknown" in warning messages. This also slightly changes what is stored in the SourceContext - now it's the actual thing (so ParameterDefinition, MethodReturnType and so on) - so printing it out doesn't require knowing which value node it came from. This is cleaner because the SourceContext describes where the value came from, not what the value is (that's the job of the ValueNode). In warnings we typically don't want to print out what the value is since in most cases we don't know the actual value (we just know things about it), so we can rely on SourceContext to simplify some code. Co-authored-by: Sven Boemer --- docs/error-codes.md | 1302 +++++++++++++++-- .../Linker.Dataflow/DiagnosticUtilities.cs | 83 +- src/linker/Linker.Dataflow/FlowAnnotations.cs | 91 +- .../ReflectionMethodBodyScanner.cs | 377 +++-- .../ReflectionPatternContext.cs | 7 +- src/linker/Linker.Dataflow/ValueNode.cs | 16 +- .../Linker.Steps/BodySubstituterStep.cs | 12 +- .../DynamicDependencyLookupStep.cs | 4 +- src/linker/Linker.Steps/LinkAttributesStep.cs | 36 +- src/linker/Linker.Steps/MarkStep.cs | 25 +- .../Linker.Steps/ProcessLinkerXmlStepBase.cs | 52 +- src/linker/Linker.Steps/ResolveFromXmlStep.cs | 16 +- .../ValidateVirtualMethodAnnotationsStep.cs | 7 +- src/linker/Linker/Annotations.cs | 3 +- src/linker/Linker/DynamicDependency.cs | 2 +- .../Linker/IReflectionPatternRecorder.cs | 3 +- .../Linker/LinkerAttributesInformation.cs | 4 +- .../LoggingReflectionPatternRecorder.cs | 4 +- test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs | 6 +- .../Assertions/ExpectedWarningAttribute.cs | 19 + ...ognizedReflectionAccessPatternAttribute.cs | 33 +- .../DataFlow/AssemblyQualifiedNameDataflow.cs | 10 +- .../DataFlow/ByRefDataflow.cs | 4 +- .../DataFlow/DynamicDependencyDataflow.cs | 4 +- .../DataFlow/EmptyArrayIntrinsicsDataFlow.cs | 6 +- .../DataFlow/FieldDataFlow.cs | 58 +- .../DataFlow/GenericParameterDataFlow.cs | 224 ++- .../DataFlow/GetTypeDataFlow.cs | 24 +- .../DataFlow/LocalDataFlow.cs | 159 +- .../DataFlow/MethodParametersDataFlow.cs | 47 +- .../DataFlow/MethodReturnParameterDataFlow.cs | 61 +- .../DataFlow/MethodThisDataFlow.cs | 133 +- .../DataFlow/PropertyDataFlow.cs | 47 +- .../SuppressWarningWithLinkAttributes.cs | 6 +- .../SuppressWarningWithLinkAttributes.xml | 2 +- ...odHierarchyDataflowAnnotationValidation.cs | 60 +- .../DataFlow/XmlAnnotations.cs | 4 +- .../DataFlow/XmlAnnotations.xml | 2 +- .../DynamicDependencyMethod.cs | 17 +- .../DynamicDependencyMethodInAssembly.cs | 4 + .../FeatureSubstitutionsInvalid.cs | 4 +- .../LinkAttributes/LinkAttributeErrorCases.cs | 76 + .../LinkAttributeErrorCases.xml | 68 + .../LinkAttributes/LinkerAttributeRemoval.cs | 13 +- .../LinkAttributes/LinkerAttributeRemoval.xml | 2 + ...dLinkXmlUnresolvedReferencesAreReported.cs | 18 +- .../LinkXml/LinkXmlErrorCases.cs | 76 + .../LinkXml/LinkXmlErrorCases.xml | 46 + .../Logging/SourceLines.cs | 16 +- .../PreserveDependencyDeprecated.cs | 8 +- .../PreserveDependencyErrorCases.cs | 40 + .../PreserveDependencyMethod.cs | 2 +- .../Reflection/ActivatorCreateInstance.cs | 56 +- .../ConstructorUsedViaReflection.cs | 7 +- .../Reflection/EventUsedViaReflection.cs | 7 +- .../Reflection/ExpressionCallString.cs | 2 +- .../Reflection/ExpressionFieldString.cs | 2 +- .../Reflection/ExpressionNewType.cs | 6 +- .../Reflection/ExpressionPropertyString.cs | 2 +- .../Reflection/FieldUsedViaReflection.cs | 7 +- .../Reflection/MethodUsedViaReflection.cs | 7 +- .../Reflection/ObjectGetType.cs | 2 +- .../Reflection/PropertyUsedViaReflection.cs | 7 +- .../RunClassConstructorUsedViaReflection.cs | 8 +- .../RuntimeReflectionExtensionsCalls.cs | 8 +- ...sUnreferencedCodeCapability.attributes.xml | 12 + .../RequiresUnreferencedCodeCapability.cs | 32 +- .../Substitutions/ResourceSubstitutions.cs | 6 +- .../Substitutions/SubstitutionsErrorCases.cs | 41 + .../Substitutions/SubstitutionsErrorCases.xml | 14 + .../Warnings/CanDisableWarnings.cs | 2 +- .../CanNotWarnAsErrorForDisabledVersion.cs | 2 +- .../Warnings/CanSetWarningVersion0.cs | 2 +- .../Warnings/CanSetWarningVersion5.cs | 2 +- .../Warnings/CanSetWarningVersion9999.cs | 2 +- .../AddSuppressionsBeforeAttributeRemoval.cs | 4 +- .../SuppressWarningsInAssembly.cs | 2 +- .../SuppressWarningsInMembersAndTypes.cs | 10 +- ...essWarningsInMembersAndTypesUsingTarget.cs | 6 +- .../SuppressWarningsInModule.cs | 2 +- .../SuppressWarningsUsingTargetViaXml.xml | 10 +- .../Extensions/CecilExtensions.cs | 14 + .../WarningSuppressionExpectations1.cs | 8 +- .../WarningSuppressionExpectations2.cs | 10 +- .../WarningSuppressionExpectations3.xml | 10 +- .../TestCasesRunner/LinkerTestLogger.cs | 12 +- .../TestCasesRunner/ResultChecker.cs | 143 +- .../TestReflectionPatternRecorder.cs | 8 +- 88 files changed, 2905 insertions(+), 913 deletions(-) create mode 100644 test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.xml create mode 100644 test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs create mode 100644 test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml create mode 100644 test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyErrorCases.cs create mode 100644 test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.attributes.xml create mode 100644 test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs create mode 100644 test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml diff --git a/docs/error-codes.md b/docs/error-codes.md index 2f3fa3f53416..ed3d8e7510e5 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -31,7 +31,7 @@ the error code. For example: #### `IL1006`: Cannot stub constructor on 'type' when base type does not have default constructor -- There was an error trying to create a new instance of type 'type'. Its construtor was marked for substitution in a substitution XML, but the base type of 'type' doesn't have a default constructor. Constructors of derived types marked for substitution require to have a default constructor in its base type. +- There was an error trying to create a new instance of type 'type'. Its constructor was marked for substitution in a substitution XML, but the base type of 'type' doesn't have a default constructor. Constructors of derived types marked for substitution require to have a default constructor in its base type. #### `IL1007`: Missing predefined 'type' type @@ -79,199 +79,675 @@ the error code. For example: #### `IL2001`: Type 'type' has no fields to preserve - The XML descriptor preserves fields on type 'type', but this type has no fields. + ```XML + + + + + + ``` + ```C# + // IL2001: Type 'TestType' has no fields to preserve + class TestType + { + void OnlyMethod() {} + } + ``` + #### `IL2002`: Type 'type' has no methods to preserve - The XML descriptor preserves methods on type 'type', but this type has no methods. -#### `IL2003`: Could not resolve 'assembly' assembly dependency specified in a 'PreserveDependency' attribute that targets method 'method' + ```XML + + + + + + ``` + ```C# + // IL2001: Type 'TestType' has no methods to preserve + struct TestType + { + public int Number; + } + ``` + +#### `IL2003`: Could not resolve dependency assembly 'assembly name' specified in a 'PreserveDependency' attribute - The assembly 'assembly' in `PreserveDependency` attribute could not be resolved. -#### `IL2004`: Could not resolve 'type' type dependency specified in a 'PreserveDependency' attribute that targets method 'method' + ```C# + // IL2003: Could not resolve dependency assembly 'NonExistentAssembly' specified in a 'PreserveDependency' attribute + [PreserveDependency("MyMethod", "MyType", "NonExistentAssembly")] + void TestMethod() + { + } + ``` + +#### `IL2004`: Could not resolve dependency type 'type' specified in a 'PreserveDependency' attribute - The type 'type' in `PreserveDependency` attribute could not be resolved. -#### `IL2005`: Could not resolve dependency member 'member' declared in type 'type' specified in a 'PreserveDependency' attribute that targets method 'method' + ```C# + // IL2004: Could not resolve dependency type 'NonExistentType' specified in a 'PreserveDependency' attribute + [PreserveDependency("MyMethod", "NonExistentType", "MyAssembly")] + void TestMethod() + { + } + ``` -- The member 'member' in `PreserveDependency` attribute could not be resolved. +#### `IL2005`: Could not resolve dependency member 'member' declared in type 'type' specified in a 'PreserveDependency' attribute -#### `IL2006` (5): Unrecognized reflection pattern +- The member 'member' in `PreserveDependency` attribute could not be resolved. -- The linker found an unrecognized reflection access pattern. The most likely reason for this is that the linker could not resolve a member that is being accessed dynamicallly. To fix this, use the `DynamicallyAccessedMemberAttribute` and specify the member kinds you're trying to access. + ```C# + // IL2005: Could not resolve dependency member 'NonExistentMethod' declared on type 'MyType' specified in a 'PreserveDependency' attribute + [PreserveDependency("NonExistentMethod", "MyType", "MyAssembly")] + void TestMethod() + { + } + ``` -#### `IL2007`: Could not resolve assembly 'assembly' specified in the 'XML document location' +#### `IL2007`: Could not resolve assembly 'assembly' - The assembly 'assembly' in the XML could not be resolved. -#### `IL2008`: Could not resolve type 'type' specified in the 'XML document location' + ```XML + + + + + ``` + +#### `IL2008`: Could not resolve type 'type' - The type 'type' in the XML could not be resolved. -#### `IL2009`: Could not find method 'method' in type 'type' specified in 'XML document location' + ```XML + + + + + + + ``` + +#### `IL2009`: Could not find method 'method' on type 'type' - The 'XML document location' defined a method 'method' on type 'type', but the method was not found. + ```XML + + + + + + + + + ``` + #### `IL2010`: Invalid value for 'signature' stub -- The value 'value' used in the substitution XML for method 'signature' does not represent a value of a built-in type, or does not match the return type of the method. +- The value used in the substitution XML for method 'signature' does not represent a value of a built-in type, or does not match the return type of the method. + + ```XML + + + + + + + + + ``` #### `IL2011`: Unknown body modification 'action' for 'signature' - The value 'action' of the body attribute used in the substitution XML is invalid (the only supported options are `remove` and `stub`). -#### `IL2012`: Could not find field 'field' in type 'type' specified in 'XML document location' + ```XML + + + + + + + + + ``` + +#### `IL2012`: Could not find field 'field' on type 'type' - The 'XML document location' defined a field 'field' on type 'type', but the field was not found. + ```XML + + + + + + + + + ``` + #### `IL2013`: Substituted field 'field' needs to be static field - The substituted field 'field' was non-static or constant. Only static non-constant fields are supported. + ```XML + + + + + + + + + ``` + #### `IL2014`: Missing 'value' attribute for field 'field' - A field was specified for substitution but no value to be substituted was given. -#### `IL2015`: Invalid value for 'field': 'value' - -- The value 'value' used in the substitution XML for field 'field' is not a built-in type, or does not match the type of 'field'. - -#### `IL2016`: Could not find event 'event' in type 'type' specified in 'XML document location' + ```XML + + + + + + + + + ``` -- The 'XML document location' defined a event 'event' on type 'type', but the event was not found. - -#### `IL2017`: Could not find property 'property' in type 'type' specified in 'XML document location' - -- The 'XML document location' defined a property 'property' on type 'type', but the property was not found. +#### `IL2015`: Invalid value 'value' for 'field' -#### `IL2018`: Could not find the get accessor of property 'property' in type 'type' specified in 'XML document location' - -- The 'XML document location' defined the get accessor of property 'property' on type 'type', but the accessor was not found. +- The value 'value' used in the substitution XML for field 'field' is not a built-in type, or does not match the type of 'field'. -#### `IL2019`: Could not find the set accessor of property 'property' in type 'type' specified in 'XML document location' + ```XML + + + + + + + + + ``` -- The 'XML document location' defined the set accessor of property 'property' on type 'type', but the accessor was not found. +#### `IL2016`: Could not find event 'event' on type 'type' -#### `IL2020`: Argument 'argument' specified in 'XML document location' is of unsupported type 'type' +- The 'XML document location' defined a event 'event' on type 'type', but the event was not found. -- The constructor parameter type is not supported in the XML reading code. + ```XML + + + + + + + + + ``` -#### `IL2021`: Could not parse argument 'argument' specified in 'XML document location' as a 'type' +#### `IL2017`: Could not find property 'property' on type 'type' -- The XML descriptor has a 'type' attribute but the argument 'argument' does not match any of the existing enum 'type' values +- The 'XML document location' defined a property 'property' on type 'type', but the property was not found. -#### `IL2022`: Could not find a constructor for type 'attribute type' that receives 'number of arguments' arguments as parameter + ```XML + + + + + + + + + ``` -- The 'attribute type' 'number of arguments' doesnt match with the number of arguments in any of the constructor function described in 'attribute type' +#### `IL2018`: Could not find the get accessor of property 'property' on type 'type' -#### `IL2023`: There is more than one return parameter specified for 'method' in 'XML document location' +- The 'XML document location' defined the get accessor of property 'property' on type 'type', but the accessor was not found. -- The XML descriptor has more than one return parameter for a single method, there can only be one return parameter + ```XML + + + + + + + + + ``` -#### `IL2024`: There are duplicate parameter names for 'parameter name' inside 'method' in 'XML document location' +#### `IL2019`: Could not find the set accessor of property 'property' on type 'type' -- The XML descriptor has more than method parameters with the same name, there can only be one return parameter +- The 'XML document location' defined the set accessor of property 'property' on type 'type', but the accessor was not found. -#### `IL2025`: Duplicate preserve of 'member' in 'XML document location' + ```XML + + + + + + + + + ``` + +#### `IL2022`: Could not find a constructor for type 'attribute type' that has 'number of arguments' arguments + +- The XML attribute for attribute type 'attribute type' specifies 'number of arguments' arguments but there's no constructor for 'attribute type' which has that many arguments + + ```XML + + + + + + ExtraArgumentValue + + + + + ``` + +#### `IL2023`: There is more than one 'return' child element specified for method 'method' + +- Method 'method' has more than one `return` element specified. There can only be one `return` element to specify attribute on the return parameter of the method. + + ```XML + + + + + + + + + + + + + + + + ``` + +#### `IL2024`: More than one value specified for parameter 'parameter' of method 'method' + +- Method 'method' has more than one `parameter` element for parameter 'parameter'. There can only be one value specified for each parameter. + + ```XML + + + + + + + + + + + + + + + + ``` + +#### `IL2025`: Duplicate preserve of 'member' - The XML descriptor marks for preservation the member or type 'member' more than once. -#### `IL2026`: Calling method annotated with `RequiresUnreferencedCodeAttribute` - -- The linker found a call to a method which is annotated with 'RequiresUnreferencedCodeAttribute' which can break functionality of a trimmed application. + ```XML + + + + + + + + + + ``` + +#### `IL2026` Trim analysis: Calling 'method' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. [message]. [url] + +- The linker found a call to a method which is annotated with `RequiresUnreferencedCodeAttribute` which can break functionality of a trimmed application. + + ```C# + [RequiresUnreferencedCode("Use 'MethodFriendlyToTrimming' instead", Url="http://help/unreferencedcode")] + void MethodWithUnreferencedCodeUsage() + { + } + + void TestMethod() + { + // IL2026: Calling 'MethodWithUnreferencedCodeUsage' which has 'RequiresUnreferencedCodeAttribute' + // can break functionality when trimming application code. Use 'MethodFriendlyToTrimming' instead. http://help/unreferencedcode + MethodWithUnreferencedCodeUsage(); + } + ``` #### `IL2027`: Attribute 'attribute' should only be used once on 'member'. - The linker found multiple instances of attribute 'attribute' on 'member'. This attribute is only allowed to have one instance, linker will only use the fist instance and ignore the rest. -#### `IL2028`: Attribute 'attribute' on 'method' doesn't have a required constructor argument. + ```C# + // Note: C# won't allow this because RequiresUnreferencedCodeAttribute only allows one instantiation, + // but it's a good demonstration (it's possible to get to this state using LinkAttributes.xml) -- The linker found an instance of attribute 'attribute' on 'method' but it lacks a required constructor argument. Linker will ignore this attribute. + // IL2027: Attribute 'RequiresUnreferencedCodeAttribute' should only be used once on 'MethodWithUnreferencedCodeUsage()'. + [RequiresUnreferencedCode("Use A instead")] + [RequiresUnreferencedCode("Use B instead")] + void MethodWithUnreferencedCodeUsage() + { + } + ``` -#### `IL2029`: Attribute element does not contain attribute 'fullname' +#### `IL2028`: Attribute 'attribute' doesn't have the required number of parameters specified -- An attribute element was declared but does not contain the attribute 'fullname' or 'fullname' attribute is empty +- The linker found an instance of attribute 'attribute' on 'method' but it lacks a required constructor parameter or it has more parameters than accepted. Linker will ignore this attribute. +This is technically possible if a custom assembly defines for example the `RequiresUnreferencedCodeAttribute` type with parameterless constructor and uses it. ILLink will recognize the attribute since it only does a namespace and type name match, but it expects it to have exactly one parameter in its constructor. -#### `IL2030`: Could not resolve assembly 'assembly' in attribute 'attribute' specified in the 'XML document location' +#### `IL2029`: 'attribute' element does not contain required attribute 'fullname' or it's empty -- The assembly 'assembly' described as a attribute property of 'attribute' could not be resolved in 'XML document location' +- An 'attribute' element must have an attribute 'fullname' with a non-empty value -#### `IL2031`: Attribute type 'attribute type' could not be found + ```XML + + + + + + + ``` -- The described 'attribute type' could not be found in the assemblies +#### `IL2030`: Could not resolve assembly 'assembly' for attribute 'attribute' -#### `IL2032`: Argument 'argument' specified in 'XML document location' could not be transformed to the constructor parameter type +- The assembly name 'assembly' specified for attribute with full name 'attribute' could not be resolved -- The number of arguments correspond to a certain type constructor, but the type of arguments specified in the xml does not match the type of arguments in the constructor. + ```XML + + + + + + + ``` -#### `IL2033`: PreserveDependencyAttribute is deprecated. Use DynamicDependencyAttribute instead. +#### `IL2031`: Attribute type 'attribute type' could not be found -- PreserveDependencyAttribute was an internal attribute that was never officially supported. Instead, use the similar DynamicDependencyAttribute. +- The described 'attribute type' could not be found in the assemblies -#### `IL2034`: Invalid DynamicDependencyAttribute on 'member' + ```XML + + + + + + + ``` -- The input contains an invalid use of DynamicDependencyAttribute. Ensure that you are using one of the officially supported constructors. +#### `IL2032`: Trim analysis: Unrecognized value passed to the parameter 'parameter' of method 'CreateInstance'. It's not possible to guarantee the availability of the target type. -#### `IL2035`: Unresolved assembly 'assemblyName' in DynamicDependencyAttribute on 'member' +- The value passed as the assembly name or type name to the `CreateInstance` method can't be statically analyzed, ILLink can't make sure that the type is available. -- The assembly string given in a DynamicDependencyAttribute constructor could not be resolved. Ensure that the argument specifies a valid asembly name, and that the assembly is available to the linker. + ``` C# + void TestMethod(string assemblyName, string typeName) + { + // IL2032 Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Activator.CreateInstance(string, string)'. It's not possible to guarantee the availability of the target type. + Activator.CreateInstance("MyAssembly", typeName); -#### `IL2036`: Unresolved type 'typeName' in DynamicDependencyAttribute on 'member' + // IL2032 Trim analysis: Unrecognized value passed to the parameter 'assemblyName' of method 'System.Activator.CreateInstance(string, string)'. It's not possible to guarantee the availability of the target type. + Activator.CreateInstance(assemblyName, "MyType"); + } + ``` -- The type in a DynamicDependencyAttribute constructor could not be resolved. Ensure that the argument specifies a valid type name or type reference, that the type exists in the specified assembly, and that the assembly is available to the linker. +#### `IL2033`: 'PreserveDependencyAttribute' is deprecated. Use 'DynamicDependencyAttribute' instead. -#### `IL2037`: No members were resolved for 'memberSignature/memberTypes'. +- `PreserveDependencyAttribute` was an internal attribute that was never officially supported. Instead, use the similar `DynamicDependencyAttribute`. -- The member signature or DynamicallyAccessedMemberTypes in a DynamicDependencyAttribute constructor did not resolve to any members on the type. If you using a signature, ensure that it refers to an existing member, and that it uses the format defined at https://github.com/dotnet/csharplang/blob/master/spec/documentation-comments.md#id-string-format. If using DynamicallyAccessedMemberTypes, ensure that the type contains members of the specified member types. + ```C# + // IL2033: 'PreserveDependencyAttribute' is deprecated. Use 'DynamicDependencyAttribute' instead. + [PreserveDependency("OtherMethod")] + public void TestMethod() + { + } + ``` -#### `IL2038`: Missing 'name' attribute for resource. +#### `IL2034`: The 'DynamicDependencyAttribute' could not be analyzed -- The resource element in a substitution file did not have a 'name' attribute. Add a 'name' attribute with the name of the resource to remove. +- The input contains an invalid use of `DynamicDependencyAttribute`. Ensure that you are using one of the officially supported constructors. +This is technically possible if a custom assembly defines `DynamicDependencyAttribute` with a different constructor than the one the ILLink recognizes. ILLink will recognize the attribute since it only does a namespace and type name match, but the actual instantiation was not recognized. -#### `IL2039`: Invalid 'action' attribute for resource 'resource'. +#### `IL2035`: Unresolved assembly 'assemblyName' in 'DynamicDependencyAttribute' -- The resource element in a substitution file did not have a valid 'action' attribute. Add an 'action' attribute to this element, with value 'remove' to tell the linker to remove this resource. +- The assembly string 'assemblyName' given in a `DynamicDependencyAttribute` constructor could not be resolved. Ensure that the argument specifies a valid assembly name, and that the assembly is available to the linker. -#### `IL2040`: Could not find embedded resource 'resource' to remove in assembly 'assembly'. + ```C# + // IL2035: Unresolved assembly 'NonExistentAssembly' in 'DynamicDependencyAttribute' + [DynamicDependency("Method", "Type", "NonExistentAssembly")] + public void TestMethod() + { + } + ``` -- The resource name in a substitution file could not be found in the specified assembly. Ensure that the resource name matches the name of an embedded resource in the assembly. +#### `IL2036`: Unresolved type 'typeName' in 'DynamicDependencyAttribute' -#### `IL2041`: DynamicallyAccessedMembersAttribute is only allowed on method parameters, return value or generic parameters. +- The type in a `DynamicDependencyAttribute` constructor could not be resolved. Ensure that the argument specifies a valid type name or type reference, that the type exists in the specified assembly, and that the assembly is available to the linker. -- DynamicallyAccessedMembersAttribute was put directly on the member itself. This is only allowed for instance methods on System.Type and similar classes. Usually this means the attribute should be placed on the return value of the method (or one of its parameters). + ```C# + // IL2036: Unresolved type 'NonExistentType' in 'DynamicDependencyAttribute' + [DynamicDependency("Method", "NonExistentType", "MyAssembly")] + public void TestMethod() + { + } + ``` -#### `IL2042`: Could not find a unique backing field for property 'property' to propagate DynamicallyAccessedMembersAttribute +#### `IL2037`: No members were resolved for 'memberSignature/memberTypes'. -- The property 'property' has DynamicallyAccessedMembersAttribute on it, but the linker could not determine the backing fields for the property to propagate the attribute to the field. +- The member signature or `DynamicallyAccessedMemberTypes` in a `DynamicDependencyAttribute` constructor did not resolve to any members on the type. If you are using a signature, ensure that it refers to an existing member, and that it uses the format defined at https://github.com/dotnet/csharplang/blob/master/spec/documentation-comments.md#id-string-format. If using `DynamicallyAccessedMemberTypes`, ensure that the type contains members of the specified member types. -#### `IL2043`: Trying to propagate DynamicallyAccessedMemberAttribute from property 'property' to its getter 'method', but it already has such attribute. + ```C# + // IL2036: No members were resolved for 'NonExistingMethod'. + [DynamicDependency("NonExistingMethod", "MyType", "MyAssembly")] + public void TestMethod() + { + } + ``` -- Propagating DynamicallyAccessedMembersAttribute from property 'property' to its getter 'method' found that the getter already has such an attribute. The existing attribute will be used. +#### `IL2038`: Missing 'name' attribute for resource. -#### `IL2044`: Could not find any type in namespace 'namespace' specified in 'XML document location' +- The `resource` element in a substitution file did not have a `name` attribute. Add a `name` attribute with the name of the resource to remove. -- The 'XML document location' specifies a namespace 'namespace' but there are no types found in such namespace. + ```XML + + + + + + + ``` -#### `IL2045`: Custom Attribute 'type' is being referenced in code but the linker was instructed to remove all instances of this attribute. If the attribute instances are necessary make sure to either remove the linker attribute XML portion which removes the attribute instances, or to override this use the linker XML descriptor to keep the attribute type (which in turn keeps all of its instances). +#### `IL2039`: Invalid value 'value' for attribute 'action' for resource 'resource'. -- CustomAttribute 'type' is being referenced in the code but the 'type' has been removed using the "remove" attribute tag on a type inside the LinkAttributes xml +- The resource element in a substitution file did not have a valid 'action' attribute. Add an 'action' attribute to this element, with value 'remove' to tell the linker to remove this resource. -#### `IL2046`: Presence of RequiresUnreferencedCodeAttribute on method 'method' doesn't match overridden method 'base method'. All overridden methods must have RequiresUnreferencedCodeAttribute. + ```XML + + + + + + + ``` -- All overrides of a virtual method including the base method must either have or not have the RequiresUnreferencedCodeAttribute. +#### `IL2040`: Could not find embedded resource 'resource' to remove in assembly 'assembly'. -#### `IL2047`: DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on don't match overridden . All overriden members must have the same DynamicallyAccessedMembersAttribute usage. +- The resource name in a substitution file could not be found in the specified assembly. Ensure that the resource name matches the name of an embedded resource in the assembly. -- All overrides of a virtual method including the base method must have the same DynamicallyAccessedMemberAttribute usage on all it's components (return value, parameters and generic parameters). + ```XML + + + + + + + ``` + +#### `IL2041` Trim analysis: The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though. + +- `DynamicallyAccessedMembersAttribute` was put directly on the method itself. This is only allowed for instance methods on System.Type and similar classes. Usually this means the attribute should be placed on the return value of the method or one of the method parameters. + + ```C# + // IL2041: The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though. + [DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicMethods)] + + // Instead if it is meant for the return value it should be done like this: + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicMethods)] + public Type GetInterestingType() + { + // ... + } + ``` + +#### `IL2042` Trim analysis: Could not find a unique backing field for property 'property' to propagate 'DynamicallyAccessedMembersAttribute' + +- The property 'property' has `DynamicallyAccessedMembersAttribute` on it, but the linker could not determine the backing field for the property to propagate the attribute to the field. + + ```C# + // IL2042: Could not find a unique backing field for property 'MyProperty' to propagate 'DynamicallyAccessedMembersAttribute' + [DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicMethods)] + public Type MyProperty + { + get { return GetTheValue(); } + set { } + } + + // To fix this annotate the accessors manually: + public Type MyProperty + { + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicMethods)] + get { return GetTheValue(); } + + [param: DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicMethods)] + set { } + } + ``` + +#### `IL2043` Trim analysis: 'DynamicallyAccessedMembersAttribute' on property 'property' conflicts with the same attribute on its accessor 'method'. + +- Propagating `DynamicallyAccessedMembersAttribute` from property 'property' to its accessor 'method' found that the accessor already has such an attribute. The existing attribute will be used. + + ```C# + // IL2043: 'DynamicallyAccessedMembersAttribute' on property 'MyProperty' conflicts with the same attribute on its accessor 'get_MyProperty'. + [DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicMethods)] + public Type MyProperty + { + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicFields)] + get { return GetTheValue(); } + } + ``` + +#### `IL2044`: Could not find any type in namespace 'namespace' + +- The XML descriptor specifies a namespace 'namespace' but there are no types found in such namespace. This typically means that the namespace is misspelled. + + ```XML + + + + + + + ``` + +#### `IL2045` Trim analysis: Attribute 'type' is being referenced in code but the linker was instructed to remove all instances of this attribute. If the attribute instances are necessary make sure to either remove the linker attribute XML portion which removes the attribute instances, or override the removal by using the linker XML descriptor to keep the attribute type (which in turn keeps all of its instances). + +- Attribute 'type' is being referenced in the code but the attribute instances have been removed using the 'RemoveAttributeInstances' internal attribute inside the LinkAttributes XML. + + ```XML + + + + + + + + ``` + + ```C# + // This attribute instance will be removed + [MyAttribute] + class MyType + { + } + + public void TestMethod() + { + // IL2045 for 'MyAttribute' reference + typeof(MyType).GetCustomAttributes(typeof(MyAttribute), false); + } + ``` + +#### `IL2046` Trim analysis: Presence of 'RequiresUnreferencedCodeAttribute' on method 'method' doesn't match overridden method 'base method'. All overridden methods must have 'RequiresUnreferencedCodeAttribute'. + +- All overrides of a virtual method including the base method must either have or not have the `RequiresUnreferencedCodeAttribute`. + + ```C# + public class Base + { + [RequiresUnreferencedCode("Message")] + public virtual void TestMethod() {} + } + + public class Derived : Base + { + // IL2046: Presence of 'RequiresUnreferencedCodeAttribute' on method 'Derived.TestMethod()' doesn't match overridden method 'Base.TestMethod'. All overridden methods must have 'RequiresUnreferencedCodeAttribute'. + public override void TestMethod() {} + } + ``` #### `IL2048`: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'member' - Internal attribute 'RemoveAttributeInstances' is a special attribute that should only be used on custom attribute types and is being used on 'member'. + ```XML + + + + + + + + + + + ``` + #### `IL2049`: Unrecognized internal attribute 'attribute' - The internal attribute name 'attribute' being used in the xml is not supported by the linker, check the spelling and the supported internal attributes. + ```XML + + + + + + + + + + + ``` + #### `IL2050`: Correctness of COM interop cannot be guaranteed - P/invoke method 'method' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed. @@ -280,14 +756,674 @@ the error code. For example: - An attribute element declares a property but this does not specify its name or is empty. + ```XML + + + + + + UnspecifiedPropertyName + + + + + ``` + #### `IL2052`: Property 'propertyName' could not be found - An attribute element has property 'propertyName' but this could not be found. + ```XML + + + + + + SomeValue + + + + + ``` + #### `IL2053`: Invalid value 'propertyValue' for property 'propertyName' - The value 'propertyValue' used in a custom attribute annotation does not match the type of the attribute's property 'propertyName'. -#### `IL2054`: Invalid argument value 'argumentValue' for attribute 'attribute' + ```XML + + + + + + StringValue + + + + + ``` + +#### `IL2054`: Invalid argument value 'argumentValue' for parameter of type 'parameterType' of attribute 'attribute' + +- The value 'argumentValue' used in a custom attribute annotation does not match the type of one of the attribute's constructor arguments. The arguments used for a custom attribute annotation should be declared in the same order the constructor uses. + + ```XML + + + + + + NonExistentEnumValue + + + + + ``` + +#### `IL2055`: Trim analysis: Call to 'System.Reflection.MethodInfo.MakeGenericType' can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. + +- This can be either that the type on which the `MakeGenericType` is called can't be statically determined, or that the type parameters to be used for generic arguments can't be statically determined. If the open generic type has `DynamicallyAccessedMembersAttribute` on any of its generic parameters, ILLink currently can't validate that the requirements are fulfilled by the calling method. + + ``` C# + class Lazy<[DynamicallyAccessedMembers(DynamicallyAccessedMemberType.PublicParameterlessConstructor)] T> + { + // ... + } + + void TestMethod(Type unknownType) + { + // IL2055 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericType(Type[])` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. + typeof(Lazy<>).MakeGenericType(new Type[] { typeof(TestType) }); + + // IL2055 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericType(Type[])` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic type. + unknownType.MakeGenericType(new Type[] { typeof(TestType) }); + } + ``` + +#### `IL2056`: Trim analysis: 'DynamicallyAccessedMemberAttribute' on property 'property' conflicts with the same attribute on its backing field 'field'. + +- Propagating `DynamicallyAccessedMembersAttribute` from property 'property' to its backing field 'field' found that the field already has such an attribute. The existing attribute will be used. + Since ILLink will only propagate to a compiler generated backing field this warning should basically never happen. The one known way requires the user code to explicitly specify the `CompilerGeneratedAttribute` on the field to get ILLink to treat it as the compiler generated backing field. + +#### `IL2057`: Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(Type typeName)'. It's not possible to guarantee the availability of the target type. + +- If the type name passed to the `System.Type.GetType` is statically known ILLink can make sure it's preserved and the application code will work after trimming. But if the type name is unknown, it could point to a type which ILLink will not see being used anywhere else and would remove it from the application, potentially breaking the application. + + ``` C# + void TestMethod() + { + string typeName = ReadName(); + + // IL2057 Trim analysis: Unrecognized value passed to the parameter 'typeName' of method 'System.Type.GetType(Type typeName)' + Type.GetType(typeName); + } + ``` + +#### `IL2058`: Trim analysis: Parameters passed to method 'Assembly.CreateInstance' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. + +- ILLink currently doesn't analyze assembly instances and thus it doesn't know on which assembly the `Assembly.CreateInstance` was called. ILLink has support for `Type.GetType` instead, for cases where the parameter is a string literal. The result of which can be passed to `Activator.CreateInstance` to create an instance of the type. + + ``` C# + void TestMethod() + { + // IL2058 Trim analysis: Parameters passed to method 'Assembly.CreateInstance(string)' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead. + AssemblyLoadContext.Default.Assemblies.First(a => a.Name == "MyAssembly").CreateInstance("MyType"); + + // This can be replaced by + Activator.CreateInstance(Type.GetType("MyType, MyAssembly")); + } + ``` + +#### `IL2059`: Trim analysis: Unrecognized value passed to the parameter 'type' of method 'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor'. It's not possible to guarantee the availability of the target static constructor. + +- If the type passed to the `RunClassConstructor` is not statically known, ILLink can't make sure that its static constructor is available. + + ``` C# + void TestMethod(Type type) + { + // IL2059 Trim analysis: Unrecognized value passed to the parameter 'type' of method 'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(RuntimeTypeHandle type)'. + // It's not possible to guarantee the availability of the target static constructor. + RuntimeHelpers.RunClassConstructor(type.TypeHandle); + } + ``` + +#### `IL2060`: Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericMethod` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. + +- ILLink currently doesn't analyze `MethodInfo` values and thus can't statically determine the generic method the `MakeGenericMethod` operates on. If the actual method has generic parameters with `DynamicallyAccessedMembersAttribute` ILLink would be required to fulfill the requirements declared by those attributes, but since the ILLink doesn't know the method, it can't determine if such requirements exist. + + ``` C# + void TestMethod() + { + // IL2060 Trim analysis: Call to `System.Reflection.MethodInfo.MakeGenericMethod` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method. + typeof(MyType).GetMethod("MyMethod").MakeGenericMethod(new Type[] { typeof(MyType) }); + } + ``` + +#### `IL2061`: Trim analysis: The assembly name 'assembly name' passed to method 'method' references assembly which is not available. + +- Calling `CreateInstance` with assembly name 'assembly name' which can't be resolved. + + ``` C# + void TestMethod() + { + // IL2061 Trim analysis: The assembly name 'NonExistentAssembly' passed to method 'System.Activator.CreateInstance(string, string)' references assembly which is not available. + Activator.CreateInstance("NonExistentAssembly", "MyType"); + } + ``` + +#### `IL2062` Trim analysis: Value passed to parameter 'parameter' of method 'method' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + +- The parameter 'parameter' of method 'method' has a `DynamicallyAccessedMembersAttribute`, but the value passed to it can not be statically analyzed. ILLink can't make sure that the requirements declared by the `DynamicallyAccessedMembersAttribute` are met by the argument value. + + ``` C# + void NeedsPublicConstructors([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + // ... + } + + void TestMethod(Type[] types) + { + // IL2062: Value passed to parameter 'type' of method 'NeedsPublicConstructors' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + NeedsPublicConstructors(types[1]); + } + ``` + +#### `IL2063`: Trim analysis: Value returned from method 'method' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + +- The return value of method 'method' has a `DynamicallyAccessedMembersAttribute`, but the value returned from the method can not be statically analyzed. ILLink can't make sure that the requirements declared by the `DynamicallyAccessedMembersAttribute` are met by the returned value. + + ``` C# + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type TestMethod(Type[] types) + { + // IL2063 Trim analysis: Value returned from method 'TestMethod' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + NeedsPublicConstructors(types[1]); + } + ``` + +#### `IL2064`: Trim analysis: Value assigned to field 'field' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + +- The field 'field' has a `DynamicallyAccessedMembersAttribute`, but the value assigned to it can not be statically analyzed. ILLink can't make sure that the requirements declared by the `DynamicallyAccessedMembersAttribute` are met by the assigned value. + + ``` C# + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type _typeField; + + void TestMethod(Type[] types) + { + // IL2064 Trim analysis: Value assigned to field '_typeField' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + _typeField = _types[1]; + } + ``` + +#### `IL2065`: Trim analysis: Value passed to implicit 'this' parameter of method 'method' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + +- The method 'method' has a `DynamicallyAccessedMembersAttribute` (which applies to the implicit 'this' parameter), but the value used for the 'this' parameter can not be statically analyzed. ILLink can't make sure that the requirements declared by the `DynamicallyAccessedMembersAttribute` are met by the 'this' value. + + ``` C# + void TestMethod(Type[] types) + { + // IL2065 Trim analysis: Value passed to implicit 'this' parameter of method 'Type.GetMethods()' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + _types[1].GetMethods (); // Type.GetMethods has [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] attribute + } + ``` + +#### `IL2066`: Trim analysis: Type passed to generic parameter 'parameter' of 'type or method' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements. + +- The generic parameter 'parameter' of 'type or method' has a `DynamicallyAccessedMembersAttribute`, but the value used for it can not be statically analyzed. ILLink can't make sure that the requirements declared by the `DynamicallyAccessedMembersAttribute` are met by the value. + +*Note: this warning can't be currently produced as there's no pure IL way to pass unknown value to a generic parameter. Once ILLInk supports full analysis of arguments for `MakeGenericType`/`MakeGenericMethod` this warnings would become active.* + +#### `IL2067`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter 'source parameter' of method 'source method' don't match those on the parameter 'target parameter' of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + void NeedsPublicConstructors([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + // ... + } + + void TestMethod(Type type) + { + // IL2006 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter 'type' of method 'TestMethod' + // don't match those on the parameter 'type' of method 'NeedsPublicConstructors'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + NeedsPublicConstructors(type); + } + ``` + +#### `IL2068`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter 'source parameter' of method 'source method' don't match those on the return value of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type TestMethod(Type type) + { + // IL2068 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on parameter 'type' of method 'TestMethod' + // don't match those on return value of method 'TestMethod'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + return type; + } + ``` + +#### `IL2069`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter 'source parameter' of method 'source method' don't match those on the field 'field'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type _typeField; + + void TestMethod(Type type) + { + // IL2069 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on parameter 'type' of method 'TestMethod' + // don't match those on field '_typeField'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + _typeField = type; + } + ``` + +#### `IL2070`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter 'source parameter' of method 'source method' don't match those on the implicit 'this' parameter of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + void TestMethod(Type type) + { + // IL2070 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on parameter 'type' of method 'TestMethod' + // don't match those on the implicit 'this' parameter of method 'Type.GetMethods()'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + type.GetMethods(); // Type.GetMethods is annotated with DynamicallyAccessedMemberTypes.PublicMethods + } + ``` + +#### `IL2071`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the parameter 'source parameter' of method 'source method' don't match those on the generic parameter 'target generic parameter' of 'target method or type'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + +#### `IL2072`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'source method' don't match those on the parameter 'target parameter' of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + Type GetCustomType() { return typeof(CustomType); } + + void NeedsPublicConstructors([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + // ... + } + + void TestMethod() + { + // IL2072 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'GetCustomType` + // don't match those on the parameter 'type' of method 'NeedsPublicConstructors'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + NeedsPublicConstructors(GetCustomType()); + } + ``` + +#### `IL2073`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'source method' don't match those on the return value of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + Type GetCustomType() { return typeof(CustomType); } + + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type TestMethod() + { + // IL2073 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'GetCustomType` + // don't match those on the return value of method 'TestMethod'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + return GetCustomType(); + } + ``` + +#### `IL2074`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'source method' don't match those on the field 'target field'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + Type GetCustomType() { return typeof(CustomType); } + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type _typeField; + + void TestMethod() + { + // IL2074 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'GetCustomType` + // don't match those on the field '_typeField'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + _typeField = GetCustomType(); + } + ``` + +#### `IL2075`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'source method' don't match those on the implicit 'this' parameter of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + Type GetCustomType() { return typeof(CustomType); } + + void TestMethod() + { + // IL2075 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'GetCustomType` + // don't match those on the implicit 'this' parameter of method 'Type.GetMethods()'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + GetCustomType().GetMethods(); // Type.GetMethods is annotated with DynamicallyAccessedMemberTypes.PublicMethods + } + ``` + +#### `IL2076`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'source method' don't match those on the generic parameter 'target generic parameter' of 'target method or type'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + +#### `IL2077`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field 'source field' don't match those on the parameter 'target parameter' of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + void NeedsPublicConstructors([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + // ... + } + + Type _typeField; + + void TestMethod() + { + // IL2075 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '_typeField' + // don't match those on the parameter 'type' of method 'NeedsPublicConstructors'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + NeedsPublicConstructors(_typeField); + } + ``` + +#### `IL2078`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field 'source field' don't match those on the return value of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + Type _typeField; + + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type TestMethod() + { + // IL2076 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '_typeField' + // don't match those on the return value of method 'TestMethod'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + _typeField; + } + ``` + +#### `IL2079`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field 'source field' don't match those on the field 'target field'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + Type _typeField; + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type _typeFieldWithRequirements; + + void TestMethod() + { + // IL2077 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '_typeField' + // don't match those on the field '_typeFieldWithRequirements'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + _typeFieldWithRequirements = _typeField; + } + ``` + +#### `IL2080`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field 'source field' don't match those on the implicit 'this' parameter of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + Type _typeField; + + void TestMethod() + { + // IL2078 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field '_typeField' + // don't match those on the implicit 'this' parameter of method 'Type.GetMethods()'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + _typeField.GetMethods(); // Type.GetMethods is annotated with DynamicallyAccessedMemberTypes.PublicMethods + } + ``` + +#### `IL2081`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the field 'source field' don't match those on the generic parameter 'target generic parameter' of 'target method or type'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + +#### `IL2082`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'source method' don't match those on the parameter 'target parameter' of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to -- The value 'argumentValue' used in a custom attribute annotation does not match the type of one of the attribute's constructor arguments. The arguments used for a custom attribute annotation should be declared in the same order the constructor uses. \ No newline at end of file +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + void NeedsPublicConstructors([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + // ... + } + + // This can only happen within methods of System.Type type (or derived types). Assume the below method is declared on System.Type + void TestMethod() + { + // IL2082 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'System.Type.TestMethod' + // don't match those on the parameter 'type' of method 'NeedsPublicConstructors'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + NeedsPublicConstructors(this); + } + ``` + +#### `IL2083`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'source method' don't match those on the return value of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + // This can only happen within methods of System.Type type (or derived types). Assume the below method is declared on System.Type + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type TestMethod() + { + // IL2083 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'System.Type.TestMethod' + // don't match those on the return value of method 'TestMethod'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + return this; + } + ``` + +#### `IL2084`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'source method' don't match those on the field 'target field'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type _typeFieldWithRequirements; + + // This can only happen within methods of System.Type type (or derived types). Assume the below method is declared on System.Type + void TestMethod() + { + // IL2084 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'System.Type.TestMethod' + // don't match those on the field '_typeFieldWithRequirements'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + _typeFieldWithRequirements = this; + } + ``` + +#### `IL2085`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'source method' don't match those on the implicit 'this' parameter of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + // This can only happen within methods of System.Type type (or derived types). Assume the below method is declared on System.Type + void TestMethod() + { + // IL2085 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'System.Type.TestMethod' + // don't match those on the implicit 'this' parameter of method 'Type.GetMethods()'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + this.GetMethods(); // Type.GetMethods is annotated with DynamicallyAccessedMemberTypes.PublicMethods + } + ``` + +#### `IL2086`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'source method' don't match those on the generic parameter 'target generic parameter' of 'target method or type'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + + +#### `IL2087`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'source generic parameter' of 'source method or type' don't match those on the parameter 'target parameter' of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + void NeedsPublicConstructors([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + // ... + } + + void TestMethod() + { + // IL2087 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'TSource' or 'TestMethod()' + // don't match those on the parameter 'type' of method 'NeedsPublicConstructors'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + NeedsPublicConstructors(typeof(TSource)); + } + ``` + +#### `IL2088`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'source generic parameter' of 'source method or type' don't match those on the return value of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type TestMethod() + { + // IL2088 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'TSource' or 'TestMethod()' + // don't match those on the return value of method 'TestMethod'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + return typeof(TSource); + } + ``` + +#### `IL2089`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'source generic parameter' of 'source method or type' don't match those on the field 'target field'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] + Type _typeFieldWithRequirements; + + void TestMethod() + { + // IL2089 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'TSource' or 'TestMethod()' + // don't match those on the field '_typeFieldWithRequirements'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + _typeFieldWithRequirements = typeof(TSource); + } + ``` + +#### `IL2090`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'source generic parameter' of 'source method or type' don't match those on the implicit 'this' parameter of method 'target method'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + void TestMethod() + { + // IL2090 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'TSource' or 'TestMethod()' + // don't match those on the implicit 'this' parameter of method 'Type.GetMethods()'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + typeof(TSource).GetMethods(); // Type.GetMethods is annotated with DynamicallyAccessedMemberTypes.PublicMethods + } + ``` + +#### `IL2091`: Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'source generic parameter' of 'source method or type' don't match those on the generic parameter 'target generic parameter' of 'target method or type'. The source value must declare at least the same requirements as those declared on the target location it's assigned to + +- The target location declares some requirements on the type value via its `DynamicallyAccessedMembersAttribute`. Those requirements must be met by those declared on the source value also via the `DynamicallyAccessedMembersAttribute`. The source value can declare more requirements than the source if necessary. + + ```C# + void NeedsPublicConstructors<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TTarget>() + { + // ... + } + + void TestMethod() + { + // IL2091 Trim analysis: The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the generic parameter 'TSource' or 'TestMethod()' + // don't match those on the generic parameter 'TTarget' of 'NeedsPublicConstructors()'. + // The source value must declare at least the same requirements as those declared on the target location it's assigned to + NeedsPublicConstructors(); + } + ``` + +#### `IL2092` Trim analysis: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter 'parameter' of method 'method' don't match overridden parameter 'parameter' of method 'base method'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + +- All overrides of a virtual method including the base method must have the same `DynamicallyAccessedMemberAttribute` usage on all it's components (return value, parameters and generic parameters). + + ```C# + public class Base + { + public virtual void TestMethod([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) {} + } + + public class Derived : Base + { + // IL2092: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter 'type' of method 'Derived.TestMethod' don't match overridden parameter 'type' of method 'Base.TestMethod'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + public override void TestMethod([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type) {} + } + ``` + +#### `IL2093` Trim analysis: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method 'method' don't match overridden return value of method 'base method'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + +- All overrides of a virtual method including the base method must have the same `DynamicallyAccessedMemberAttribute` usage on all it's components (return value, parameters and generic parameters). + + ```C# + public class Base + { + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + public virtual Type TestMethod() {} + } + + public class Derived : Base + { + // IL2093: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method 'Derived.TestMethod' don't match overridden return value of method 'Base.TestMethod'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + public override Type TestMethod() {} + } + ``` + +#### `IL2094`: Trim analysis: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'method' don't match overridden implicit 'this' parameter of method 'base method'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + +- All overrides of a virtual method including the base method must have the same `DynamicallyAccessedMemberAttribute` usage on all it's components (return value, parameters and generic parameters). + + ```C# + // This only works on methods in System.Type and derived classes - this is just an example + public class Type + { + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + public virtual void TestMethod() {} + } + + public class DerivedType : Type + { + // IL2094: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method 'DerivedType.TestMethod' don't match overridden implicit 'this' parameter of method 'Type.TestMethod'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + public override void TestMethod() {} + } + ``` + +#### `IL2095`: Trim analysis: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the generic parameter 'generic parameter' of 'method' don't match overridden generic parameter 'generic parameter' of 'base method'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + +- All overrides of a virtual method including the base method must have the same `DynamicallyAccessedMemberAttribute` usage on all it's components (return value, parameters and generic parameters). + + ```C# + public class Base + { + public virtual void TestMethod<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>() {} + } + + public class Derived : Base + { + // IL2095: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the generic parameter 'T' of method 'Derived.TestMethod' don't match overridden generic parameter 'T' of method 'Base.TestMethod'. All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage. + public override void TestMethod<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>() {} + } + ``` diff --git a/src/linker/Linker.Dataflow/DiagnosticUtilities.cs b/src/linker/Linker.Dataflow/DiagnosticUtilities.cs index 231e28cb7d33..a6fe384233e3 100644 --- a/src/linker/Linker.Dataflow/DiagnosticUtilities.cs +++ b/src/linker/Linker.Dataflow/DiagnosticUtilities.cs @@ -2,65 +2,12 @@ // 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.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; using Mono.Cecil; namespace Mono.Linker.Dataflow { static class DiagnosticUtilities { - internal static string GetDynamicallyAccessedMemberTypesDescription (DynamicallyAccessedMemberTypes memberTypes) - { - if (memberTypes == DynamicallyAccessedMemberTypes.All) - return DynamicallyAccessedMemberTypes.All.ToString (); - - var results = new List (); - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicConstructors)) - results.Add (DynamicallyAccessedMemberTypes.NonPublicConstructors); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors)) - results.Add (DynamicallyAccessedMemberTypes.PublicConstructors); - else if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)) - results.Add (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicMethods)) - results.Add (DynamicallyAccessedMemberTypes.NonPublicMethods); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicMethods)) - results.Add (DynamicallyAccessedMemberTypes.PublicMethods); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicProperties)) - results.Add (DynamicallyAccessedMemberTypes.NonPublicProperties); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicProperties)) - results.Add (DynamicallyAccessedMemberTypes.PublicProperties); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicFields)) - results.Add (DynamicallyAccessedMemberTypes.NonPublicFields); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicFields)) - results.Add (DynamicallyAccessedMemberTypes.PublicFields); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicEvents)) - results.Add (DynamicallyAccessedMemberTypes.NonPublicEvents); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicEvents)) - results.Add (DynamicallyAccessedMemberTypes.PublicEvents); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicNestedTypes)) - results.Add (DynamicallyAccessedMemberTypes.NonPublicNestedTypes); - - if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicNestedTypes)) - results.Add (DynamicallyAccessedMemberTypes.PublicNestedTypes); - - if (results.Count == 0) - return DynamicallyAccessedMemberTypes.None.ToString (); - - return string.Join (" | ", results.Select (r => r.ToString ())); - } - internal static IMetadataTokenProvider GetMethodParameterFromIndex (MethodDefinition method, int parameterIndex) { int declaredParameterIndex; @@ -78,35 +25,15 @@ internal static IMetadataTokenProvider GetMethodParameterFromIndex (MethodDefini return null; } - internal static string GetMetadataTokenDescriptionForErrorMessage (IMetadataTokenProvider targetContext) => - targetContext switch - { - ParameterDefinition parameterDefinition => GetParameterDescriptionForErrorMessage (parameterDefinition), - MethodReturnType methodReturnType => $"return value of method '{GetMethodSignatureDisplayName (methodReturnType.Method)}'", - FieldDefinition fieldDefinition => $"field '{fieldDefinition}'", - // MethodDefinition is used to represent the "this" parameter as we don't support annotations on the method itself. - MethodDefinition methodDefinition => $"implicit 'this' parameter of method '{methodDefinition.GetDisplayName ()}'", - GenericParameter genericParameter => GetGenericParameterDescriptionForErrorMessage (genericParameter), - _ => $"'{targetContext}'", - }; + internal static string GetParameterNameForErrorMessage (ParameterDefinition parameterDefinition) => + string.IsNullOrEmpty (parameterDefinition.Name) ? $"#{parameterDefinition.Index}" : parameterDefinition.Name; - static string GetParameterDescriptionForErrorMessage (ParameterDefinition parameterDefinition) - { - if (string.IsNullOrEmpty (parameterDefinition.Name)) - return $"parameter #{parameterDefinition.Index} of method '{GetMethodSignatureDisplayName (parameterDefinition.Method)}'"; - else - return $"parameter '{parameterDefinition.Name}' of method '{GetMethodSignatureDisplayName (parameterDefinition.Method)}'"; - } - - static string GetGenericParameterDescriptionForErrorMessage (GenericParameter genericParameter) - { - var declaringMemberName = genericParameter.DeclaringMethod != null ? + internal static string GetGenericParameterDeclaringMemberDisplayName (GenericParameter genericParameter) => + genericParameter.DeclaringMethod != null ? genericParameter.DeclaringMethod.GetDisplayName () : genericParameter.DeclaringType.GetDisplayName (); - return $"generic parameter '{genericParameter.Name}' from '{declaringMemberName}'"; - } - static string GetMethodSignatureDisplayName (IMethodSignature methodSignature) => + internal static string GetMethodSignatureDisplayName (IMethodSignature methodSignature) => (methodSignature is MethodDefinition method) ? method.GetDisplayName () : methodSignature.ToString (); } } diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs index d7566f37161a..5234b23d826f 100644 --- a/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -2,7 +2,9 @@ // 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; using System.Diagnostics.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; @@ -101,7 +103,7 @@ static bool IsDynamicallyAccessedMembersAttribute (CustomAttribute attribute) return attributeType.Name == "DynamicallyAccessedMembersAttribute" && attributeType.Namespace == "System.Diagnostics.CodeAnalysis"; } - DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ICustomAttributeProvider provider, IMemberDefinition locationMember = null) + DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMembersAttribute (ICustomAttributeProvider provider, IMemberDefinition locationMember = null) { if (!_context.CustomAttributes.HasCustomAttributes (provider)) return DynamicallyAccessedMemberTypes.None; @@ -110,10 +112,10 @@ DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribu continue; if (attribute.ConstructorArguments.Count == 1) return (DynamicallyAccessedMemberTypes) (int) attribute.ConstructorArguments[0].Value; - else if (attribute.ConstructorArguments.Count == 0) - _context.LogWarning ($"DynamicallyAccessedMembersAttribute was specified but no argument was proportioned", 2020, locationMember ?? (provider as IMemberDefinition)); else - _context.LogWarning ($"DynamicallyAccessedMembersAttribute was specified but there is more than one argument", 2022, locationMember ?? (provider as IMemberDefinition)); + _context.LogWarning ( + $"Attribute 'System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute' doesn't have the required number of parameters specified", + 2028, locationMember ?? (provider as IMemberDefinition)); } return DynamicallyAccessedMemberTypes.None; } @@ -128,7 +130,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (!IsTypeInterestingForDataflow (field.FieldType)) continue; - DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (field); + DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (field); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } @@ -148,7 +150,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) // IL space assigns index 0 to the `this` parameter on instance methods. - DynamicallyAccessedMemberTypes methodMemberTypes = GetMemberTypesForDynamicallyAccessedMemberAttribute (method); + DynamicallyAccessedMemberTypes methodMemberTypes = GetMemberTypesForDynamicallyAccessedMembersAttribute (method); int offset; if (method.HasImplicitThis ()) { @@ -161,12 +163,16 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) paramAnnotations[0] = methodMemberTypes; } } else if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) { - _context.LogWarning ($"The DynamicallyAccessedMembersAttribute is only allowed on method parameters, return value or generic parameters.", 2041, method); + _context.LogWarning ( + $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.", + 2041, method, subcategory: MessageSubCategory.TrimAnalysis); } } else { offset = 0; if (methodMemberTypes != DynamicallyAccessedMemberTypes.None) { - _context.LogWarning ($"The DynamicallyAccessedMembersAttribute is only allowed on method parameters, return value or generic parameters.", 2041, method); + _context.LogWarning ( + $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.", + 2041, method, subcategory: MessageSubCategory.TrimAnalysis); } } @@ -175,7 +181,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) continue; } - DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMemberAttribute (method.Parameters[i], method); + DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMembersAttribute (method.Parameters[i], method); if (pa == DynamicallyAccessedMemberTypes.None) { continue; } @@ -187,13 +193,13 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) } DynamicallyAccessedMemberTypes returnAnnotation = IsTypeInterestingForDataflow (method.ReturnType) ? - GetMemberTypesForDynamicallyAccessedMemberAttribute (method.MethodReturnType, method) : DynamicallyAccessedMemberTypes.None; + GetMemberTypesForDynamicallyAccessedMembersAttribute (method.MethodReturnType, method) : DynamicallyAccessedMemberTypes.None; DynamicallyAccessedMemberTypes[] genericParameterAnnotations = null; if (method.HasGenericParameters) { for (int genericParameterIndex = 0; genericParameterIndex < method.GenericParameters.Count; genericParameterIndex++) { var genericParameter = method.GenericParameters[genericParameterIndex]; - var annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (genericParameter, method); + var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (genericParameter, method); if (annotation != DynamicallyAccessedMemberTypes.None) { if (genericParameterAnnotations == null) genericParameterAnnotations = new DynamicallyAccessedMemberTypes[method.GenericParameters.Count]; @@ -229,7 +235,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) continue; } - DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (property); + DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (property); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } @@ -250,7 +256,9 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) } if (annotatedMethods.Any (a => a.Method == setMethod)) { - _context.LogWarning ($"Trying to propagate DynamicallyAccessedMemberAttribute from property '{property.FullName}' to its setter '{setMethod.GetDisplayName ()}', but it already has such attribute on the 'value' parameter.", 2043, setMethod); + _context.LogWarning ( + $"'DynamicallyAccessedMembersAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its accessor '{setMethod.GetDisplayName ()}'.", + 2043, setMethod, subcategory: MessageSubCategory.TrimAnalysis); } else { int offset = setMethod.HasImplicitThis () ? 1 : 0; if (setMethod.Parameters.Count > 0) { @@ -277,7 +285,8 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) } if (annotatedMethods.Any (a => a.Method == getMethod)) { - _context.LogWarning ($"Trying to propagate DynamicallyAccessedMemberAttribute from property '{property.FullName}' to its getter '{getMethod.GetDisplayName ()}', but it already has such attribute on the return value.", + _context.LogWarning ( + $"'DynamicallyAccessedMembersAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its accessor '{getMethod.GetDisplayName ()}'.", 2043, getMethod, subcategory: MessageSubCategory.TrimAnalysis); } else { annotatedMethods.Add (new MethodAnnotations (getMethod, null, annotation, null)); @@ -287,7 +296,9 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) FieldDefinition backingField; if (backingFieldFromGetter != null && backingFieldFromSetter != null && backingFieldFromGetter != backingFieldFromSetter) { - _context.LogWarning ($"Could not find a unique backing field for property '{property.FullName}' to propagate DynamicallyAccessedMembersAttribute. The backing fields from getter '{backingFieldFromGetter.FullName}' and setter '{backingFieldFromSetter.FullName}' are not the same.", 2042, property); + _context.LogWarning ( + $"Could not find a unique backing field for property '{property.GetDisplayName ()}' to propagate 'DynamicallyAccessedMembersAttribute'.", + 2042, property, subcategory: MessageSubCategory.TrimAnalysis); backingField = null; } else { backingField = backingFieldFromGetter ?? backingFieldFromSetter; @@ -295,8 +306,9 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (backingField != null) { if (annotatedFields.Any (a => a.Field == backingField)) { - _context.LogWarning ($"Trying to propagate DynamicallyAccessedMemberAttribute from property '{property.FullName}' to its field '{backingField}', but it already has such attribute.", - 2043, backingField, subcategory: MessageSubCategory.TrimAnalysis); + _context.LogWarning ( + $"'DynamicallyAccessedMemberAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its backing field '{backingField.GetDisplayName ()}'.", + 2056, backingField, subcategory: MessageSubCategory.TrimAnalysis); } else { annotatedFields.Add (new FieldAnnotation (backingField, annotation)); } @@ -308,7 +320,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (type.HasGenericParameters) { for (int genericParameterIndex = 0; genericParameterIndex < type.GenericParameters.Count; genericParameterIndex++) { var genericParameter = type.GenericParameters[genericParameterIndex]; - var annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (genericParameter, type); + var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (genericParameter, type); if (annotation != DynamicallyAccessedMemberTypes.None) { if (typeGenericParameterAnnotations == null) typeGenericParameterAnnotations = new DynamicallyAccessedMemberTypes[type.GenericParameters.Count]; @@ -455,12 +467,43 @@ void ValidateMethodGenericParametersHaveNoAnnotations (ref MethodAnnotations met void LogValidationWarning (IMetadataTokenProvider provider, IMetadataTokenProvider baseProvider, IMemberDefinition origin) { - _context.LogWarning ( - $"DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on {DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (provider)} " + - $"don't match overridden {DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (baseProvider)}. " + - $"All overridden members must have the same DynamicallyAccessedMembersAttribute usage.", - 2047, - origin); + Debug.Assert (provider.GetType () == baseProvider.GetType ()); + Debug.Assert (!(provider is GenericParameter genericParameter) || genericParameter.DeclaringMethod != null); + switch (provider) { + case ParameterDefinition parameterDefinition: + var baseParameterDefinition = (ParameterDefinition) baseProvider; + _context.LogWarning ( + $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (parameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (parameterDefinition.Method)}' " + + $"don't match overridden parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (baseParameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (baseParameterDefinition.Method)}'. " + + $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.", + 2092, origin, subcategory: MessageSubCategory.TrimAnalysis); + break; + case MethodReturnType methodReturnType: + _context.LogWarning ( + $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodReturnType.Method)}' " + + $"don't match overridden return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (((MethodReturnType) baseProvider).Method)}'. " + + $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.", + 2093, origin, subcategory: MessageSubCategory.TrimAnalysis); + break; + // No fields - it's not possible to have a virtual field and override it + case MethodDefinition methodDefinition: + _context.LogWarning ( + $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodDefinition)}' " + + $"don't match overridden implicit 'this' parameter of method '{DiagnosticUtilities.GetMethodSignatureDisplayName ((MethodDefinition) baseProvider)}'. " + + $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.", + 2094, origin, subcategory: MessageSubCategory.TrimAnalysis); + break; + case GenericParameter genericParameterOverride: + var genericParameterBase = (GenericParameter) baseProvider; + _context.LogWarning ( + $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the generic parameter '{genericParameterOverride.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterOverride)}' " + + $"don't match overridden generic parameter '{genericParameterBase.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterBase)}'. " + + $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.", + 2095, origin, subcategory: MessageSubCategory.TrimAnalysis); + break; + default: + throw new NotImplementedException ($"Unsupported provider type{provider.GetType ()}"); + } } readonly struct TypeAnnotations diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index 73a103bcc0d0..c81e86e47bff 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -68,7 +68,7 @@ public void ScanAndProcessReturnValue (MethodBody methodBody) { Scan (methodBody); - if (MethodReturnValue != null) { + if (methodBody.Method.ReturnType.MetadataType != MetadataType.Void) { var method = methodBody.Method; var requiredMemberTypes = _context.Annotations.FlowAnnotations.GetReturnParameterAnnotation (method); if (requiredMemberTypes != 0) { @@ -130,27 +130,28 @@ public void ProcessGenericArgumentDataFlow (GenericParameter genericParameter, T var annotation = _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameter); Debug.Assert (annotation != DynamicallyAccessedMemberTypes.None); - ValueNode valueNode; + ValueNode valueNode = GetValueNodeFromGenericArgument (genericArgument); + bool enableReflectionPatternReporting = !(source is MethodDefinition sourceMethod) || ShouldEnableReflectionPatternReporting (sourceMethod); + + var reflectionContext = new ReflectionPatternContext (_context, enableReflectionPatternReporting, source, genericParameter); + reflectionContext.AnalyzingPattern (); + RequireDynamicallyAccessedMembers (ref reflectionContext, annotation, valueNode, genericParameter); + } + + ValueNode GetValueNodeFromGenericArgument (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. - valueNode = new SystemTypeForGenericParameterValue (inputGenericParameter, _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (inputGenericParameter)); + return new SystemTypeForGenericParameterValue (inputGenericParameter, _context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (inputGenericParameter)); } else { TypeDefinition genericArgumentTypeDef = genericArgument.Resolve (); if (genericArgumentTypeDef != null) { - valueNode = new SystemTypeValue (genericArgumentTypeDef); + return new SystemTypeValue (genericArgumentTypeDef); } else { throw new InvalidOperationException (); } } - - if (valueNode != null) { - bool enableReflectionPatternReporting = !(source is MethodDefinition sourceMethod) || ShouldEnableReflectionPatternReporting (sourceMethod); - - var reflectionContext = new ReflectionPatternContext (_context, enableReflectionPatternReporting, source, genericParameter); - reflectionContext.AnalyzingPattern (); - RequireDynamicallyAccessedMembers (ref reflectionContext, annotation, valueNode, genericParameter); - } } protected override void WarnAboutInvalidILInMethod (MethodBody method, int ilOffset) @@ -167,9 +168,7 @@ protected override void WarnAboutInvalidILInMethod (MethodBody method, int ilOff protected override ValueNode GetMethodParameterValue (MethodDefinition method, int parameterIndex) { DynamicallyAccessedMemberTypes memberTypes = _context.Annotations.FlowAnnotations.GetParameterAnnotation (method, parameterIndex); - return new MethodParameterValue (parameterIndex, memberTypes) { - SourceContext = method - }; + return new MethodParameterValue (parameterIndex, memberTypes, DiagnosticUtilities.GetMethodParameterFromIndex (method, parameterIndex)); } protected override ValueNode GetFieldValue (MethodDefinition method, FieldDefinition field) @@ -181,9 +180,7 @@ protected override ValueNode GetFieldValue (MethodDefinition method, FieldDefini default: { DynamicallyAccessedMemberTypes memberTypes = _context.Annotations.FlowAnnotations.GetFieldAnnotation (field); - return new LoadFieldValue (field, memberTypes) { - SourceContext = method - }; + return new LoadFieldValue (field, memberTypes); } } } @@ -430,6 +427,7 @@ static IntrinsicId GetIntrinsicIdForMethod (MethodDefinition calledMethod) // static T System.Activator.CreateInstance () "CreateInstance" when calledMethod.IsDeclaredOnType ("System", "Activator") && calledMethod.ContainsGenericParameter + && calledMethod.GenericParameters.Count == 1 && calledMethod.Parameters.Count == 0 => IntrinsicId.Activator_CreateInstanceOfT, @@ -559,7 +557,10 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c if (_context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameter) != DynamicallyAccessedMemberTypes.None) { // There is a generic parameter which has some requirements on the input types. // For now we don't support tracking actual array elements, so we can't validate that the requirements are fulfilled. - reflectionContext.RecordUnrecognizedPattern ($"Calling to 'System.Type.MakeGenericType' on type '{typeValue.TypeRepresented.GetDisplayName ()}' is not recognized due to presense of DynamicallyAccessedMembersAttribute on some of the generic parameters."); + reflectionContext.RecordUnrecognizedPattern ( + 2055, + $"Call to '{calledMethodDefinition.GetDisplayName ()}' can not be statically analyzed. " + + $"It's not possible to guarantee the availability of requirements of the generic type."); } } @@ -569,7 +570,10 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c reflectionContext.RecordHandledPattern (); else { // We have no way to "include more" to fix this if we don't know, so we have to warn - reflectionContext.RecordUnrecognizedPattern ($"Calling to 'System.Type.MakeGenericType' on unrecognized value."); + reflectionContext.RecordUnrecognizedPattern ( + 2055, + $"Call to '{calledMethodDefinition.GetDisplayName ()}' can not be statically analyzed. " + + $"It's not possible to guarantee the availability of requirements of the generic type."); } } @@ -797,15 +801,11 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c reflectionContext.RecordHandledPattern (); } else if (typeNameValue is LeafValueWithDynamicallyAccessedMemberNode valueWithDynamicallyAccessedMember && valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes != 0) { // Propagate the annotation from the type name to the return value. Annotation on a string value will be fullfilled 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 fullfill the annotation. + // So while we don't know which type it is, we can guarantee that it will fulfill the annotation. reflectionContext.RecordHandledPattern (); - methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new MethodReturnValue (valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes) { - SourceContext = calledMethod.Parameters[0] - }); + methodReturnValue = MergePointValue.MergeValues (methodReturnValue, new MethodReturnValue (calledMethodDefinition.MethodReturnType, valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes)); } else { - reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{calledMethod.GetDisplayName ()}' inside " + - $"'{((reflectionContext.Source is MethodDefinition method) ? method.GetDisplayName () : reflectionContext.Source.ToString ())}' " + - $"was detected with unknown value for the type name."); + reflectionContext.RecordUnrecognizedPattern (2057, $"Unrecognized value passed to the parameter 'typeName' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); } } @@ -947,7 +947,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c ValueNode transformedResult = null; foreach (var value in methodParams[0].UniqueValues ()) { if (value is LeafValueWithDynamicallyAccessedMemberNode dynamicallyAccessedThing) { - var annotatedString = new AnnotatedStringValue (dynamicallyAccessedThing.DynamicallyAccessedMemberTypes); + var annotatedString = new AnnotatedStringValue (dynamicallyAccessedThing.SourceContext, dynamicallyAccessedThing.DynamicallyAccessedMemberTypes); transformedResult = MergePointValue.MergeValues (transformedResult, annotatedString); } else { transformedResult = null; @@ -1133,26 +1133,23 @@ methodParams[argsParam] is ArrayValue arrayValue && // // static T CreateInstance () // - case IntrinsicId.Activator_CreateInstanceOfT: { + // Note: If the when condition returns false it would be an overload which we don't recognize, so just fall through to the default case + case IntrinsicId.Activator_CreateInstanceOfT when + calledMethod is GenericInstanceMethod genericCalledMethod && genericCalledMethod.GenericArguments.Count == 1: { reflectionContext.AnalyzingPattern (); - if (calledMethod is GenericInstanceMethod genericCalledMethod && genericCalledMethod.GenericArguments.Count == 1 - && genericCalledMethod.GenericArguments[0] is GenericParameter genericParameter) { - if (genericParameter.HasDefaultConstructorConstraint) { - // This is safe, the linker would have marked the default .ctor already - reflectionContext.RecordHandledPattern (); - break; - } - - if ((_context.Annotations.FlowAnnotations.GetGenericParameterAnnotation (genericParameter) & DynamicallyAccessedMemberTypes.PublicParameterlessConstructor) != 0) { - // Also safe, the linker would have marked the default .ctor already - reflectionContext.RecordHandledPattern (); - break; - } + if (genericCalledMethod.GenericArguments[0] is GenericParameter genericParameter && + genericParameter.HasDefaultConstructorConstraint) { + // This is safe, the linker would have marked the default .ctor already + reflectionContext.RecordHandledPattern (); + break; } - // Not yet supported in any combination - reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MemberWithRequirements}' inside '{reflectionContext.Source}' is not recognized, the type to instantiate may be missing the necessary constructor."); + RequireDynamicallyAccessedMembers ( + ref reflectionContext, + DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, + GetValueNodeFromGenericArgument (genericCalledMethod.GenericArguments[0]), + calledMethodDefinition.GenericParameters[0]); } break; @@ -1194,7 +1191,7 @@ methodParams[argsParam] is ArrayValue arrayValue && // TODO: This could be supported for "this" only calls // reflectionContext.AnalyzingPattern (); - reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MemberWithRequirements}' inside '{reflectionContext.Source}' is not yet supported"); + reflectionContext.RecordUnrecognizedPattern (2058, $"Parameters passed to method '{calledMethodDefinition.GetDisplayName ()}' cannot be analyzed. Consider using methods 'System.Type.GetType' and `System.Activator.CreateInstance` instead."); break; // @@ -1211,9 +1208,7 @@ methodParams[argsParam] is ArrayValue arrayValue && } else if (typeHandleValue == NullValue.Instance) reflectionContext.RecordHandledPattern (); else { - reflectionContext.RecordUnrecognizedPattern ($"A {GetValueDescriptionForErrorMessage (typeHandleValue)} " + - $"is passed into the {DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage ((reflectionContext.MemberWithRequirements as MethodDefinition).Parameters[0])}. " + - $"It's not possible to guarantee availability of the target static constructor."); + reflectionContext.RecordUnrecognizedPattern (2059, $"Unrecognized value passed to the parameter 'type' of method '{calledMethodDefinition.GetDisplayName ()}'. It's not possible to guarantee the availability of the target static constructor."); } } } @@ -1229,7 +1224,7 @@ methodParams[argsParam] is ArrayValue arrayValue && // We don't track MethodInfo values, so we can't determine if the MakeGenericMethod is problematic or not. // Since some of the generic parameters may have annotations, all calls are potentially dangerous. - reflectionContext.RecordUnrecognizedPattern ($"Call to 'System.Reflection.MethodInfo.MakeGenericMethod' is not recognized."); + reflectionContext.RecordUnrecognizedPattern (2060, $"Call to `{calledMethod.GetDisplayName ()}` can not be statically analyzed. It's not possible to guarantee the availability of requirements of the generic method."); } break; @@ -1272,9 +1267,7 @@ methodParams[argsParam] is ArrayValue arrayValue && // To get good reporting of errors we need to track the origin of the value for all method calls // but except Newobj as those are special. if (calledMethodDefinition.ReturnType.MetadataType != MetadataType.Void) { - methodReturnValue = new MethodReturnValue (returnValueDynamicallyAccessedMemberTypes) { - SourceContext = calledMethodDefinition - }; + methodReturnValue = new MethodReturnValue (calledMethodDefinition.MethodReturnType, returnValueDynamicallyAccessedMemberTypes); return true; } @@ -1290,9 +1283,7 @@ methodParams[argsParam] is ArrayValue arrayValue && // unknown value with the return type of the method. if (methodReturnValue == null) { if (calledMethod.ReturnType.MetadataType != MetadataType.Void) { - methodReturnValue = new MethodReturnValue (returnValueDynamicallyAccessedMemberTypes) { - SourceContext = calledMethodDefinition - }; + methodReturnValue = new MethodReturnValue (calledMethodDefinition.MethodReturnType, returnValueDynamicallyAccessedMemberTypes); } } @@ -1332,24 +1323,27 @@ void ProcessCreateInstanceByName (ref ReflectionPatternContext reflectionContext if (typeNameValue is KnownStringValue typeNameStringValue) { var resolvedAssembly = _context.GetLoadedAssembly (assemblyNameStringValue.Contents); if (resolvedAssembly == null) { - reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MemberWithRequirements}' inside '{reflectionContext.Source}' references assembly '{assemblyNameStringValue.Contents}' which could not be found"); + reflectionContext.RecordUnrecognizedPattern (2061, $"The assembly name '{assemblyNameStringValue.Contents}' passed to method '{calledMethod.GetDisplayName ()}' references assembly which is not available."); continue; } var resolvedType = resolvedAssembly.FindType (typeNameStringValue.Contents); if (resolvedType == null) { - reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MemberWithRequirements}' inside '{reflectionContext.Source}' references type '{typeNameStringValue}' in assembly '{resolvedAssembly.FullName}' which could not be found"); + // 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. + reflectionContext.RecordHandledPattern (); continue; } MarkConstructorsOnType (ref reflectionContext, resolvedType, parameterlessConstructor ? m => m.Parameters.Count == 0 : (Func) null, bindingFlags); } else { - reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MemberWithRequirements}' inside '{reflectionContext.Source}' has unrecognized value for the 'typeName' parameter."); + reflectionContext.RecordUnrecognizedPattern (2032, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[1].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); } } } else { - reflectionContext.RecordUnrecognizedPattern ($"Activator call '{reflectionContext.MemberWithRequirements}' inside '{reflectionContext.Source}' has unrecognized value for the 'assemblyName' parameter."); + reflectionContext.RecordUnrecognizedPattern (2032, $"Unrecognized value passed to the parameter '{calledMethod.Parameters[0].Name}' of method '{calledMethod.GetDisplayName ()}'. It's not possible to guarantee the availability of the target type."); } } } @@ -1364,11 +1358,201 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC reflectionContext.RecordHandledPattern (); } else if (uniqueValue is LeafValueWithDynamicallyAccessedMemberNode valueWithDynamicallyAccessedMember) { if (!valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes.HasFlag (requiredMemberTypes)) { - reflectionContext.RecordUnrecognizedPattern ($"The {GetValueDescriptionForErrorMessage (valueWithDynamicallyAccessedMember)} " + - $"with dynamically accessed member kinds '{DiagnosticUtilities.GetDynamicallyAccessedMemberTypesDescription (valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes)}' " + - $"is passed into the {DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (targetContext)} " + - $"which requires dynamically accessed member kinds '{DiagnosticUtilities.GetDynamicallyAccessedMemberTypesDescription (requiredMemberTypes)}'. " + - $"To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds '{DiagnosticUtilities.GetDynamicallyAccessedMemberTypesDescription (requiredMemberTypes)}'."); + switch ((valueWithDynamicallyAccessedMember.SourceContext, targetContext)) { + case (ParameterDefinition sourceParameter, ParameterDefinition targetParameter): + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + 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 "); + 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 "); + 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 "); + break; + case (ParameterDefinition sourceParameter, GenericParameter targetGenericParameter): + // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + break; + + case (MethodReturnType sourceMethodReturnType, ParameterDefinition targetParameter): + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + 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 "); + 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 "); + 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 "); + break; + case (MethodReturnType sourceMethodReturnType, GenericParameter targetGenericParameter): + // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + break; + + case (FieldDefinition sourceField, ParameterDefinition targetParameter): + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + 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 "); + 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 "); + 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 "); + break; + case (FieldDefinition sourceField, GenericParameter targetGenericParameter): + // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + break; + + case (MethodDefinition sourceMethod, ParameterDefinition targetParameter): + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + 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 "); + 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 "); + 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 "); + break; + case (MethodDefinition sourceMethod, GenericParameter targetGenericParameter): + // Currently this is never generated, once ILLink supports full analysis of MakeGenericType/MakeGenericMethod this will be used + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + break; + + case (GenericParameter sourceGenericParameter, ParameterDefinition targetParameter): + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + 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 "); + 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 "); + 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 + // For example code like this should ideally one day generate the warning + // void TestMethod() + // { + // // This passes the T as the "this" parameter to Type.GetMethods() + // typeof(Type).GetMethod("GetMethods").Invoke(typeof(T), new object[] {}); + // } + reflectionContext.RecordUnrecognizedPattern ( + 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 "); + 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 "); + break; + + default: + throw new NotImplementedException ($"unsupported source context {valueWithDynamicallyAccessedMember.SourceContext} or target context {targetContext}"); + }; } else { reflectionContext.RecordHandledPattern (); } @@ -1385,10 +1569,36 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC } else if (uniqueValue == NullValue.Instance) { // Ignore - probably unreachable path as it would fail at runtime anyway. } else { - reflectionContext.RecordUnrecognizedPattern ($"A {GetValueDescriptionForErrorMessage (uniqueValue)} " + - $"is passed into the {DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (targetContext)} " + - $"which requires dynamically accessed member kinds '{DiagnosticUtilities.GetDynamicallyAccessedMemberTypesDescription (requiredMemberTypes)}'. " + - $"It's not possible to guarantee that these requirements are met by the application."); + switch (targetContext) { + case ParameterDefinition parameterDefinition: + reflectionContext.RecordUnrecognizedPattern ( + 2062, + $"Value passed to parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (parameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (parameterDefinition.Method)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements."); + break; + case MethodReturnType methodReturnType: + reflectionContext.RecordUnrecognizedPattern ( + 2063, + $"Value returned from method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodReturnType.Method)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements."); + break; + case FieldDefinition fieldDefinition: + reflectionContext.RecordUnrecognizedPattern ( + 2064, + $"Value assigned to {fieldDefinition.GetDisplayName ()} can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements."); + break; + case MethodDefinition methodDefinition: + reflectionContext.RecordUnrecognizedPattern ( + 2065, + $"Value passed to implicit 'this' parameter of method '{methodDefinition.GetDisplayName ()}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements."); + break; + case GenericParameter genericParameter: + // Note: this is currently unreachable as there's no IL way to pass unknown value to a generic parameter without using reflection. + // Once we support analysis of MakeGenericType/MakeGenericMethod arguments this would become reachable though. + reflectionContext.RecordUnrecognizedPattern ( + 2066, + $"Type passed to generic parameter '{genericParameter.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameter)}' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements."); + break; + default: throw new NotImplementedException ($"unsupported target context {targetContext.GetType ()}"); + }; } } @@ -1514,35 +1724,6 @@ void MarkEventsOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, MarkEvent (ref reflectionContext, @event); } - string GetValueDescriptionForErrorMessage (ValueNode value) - { - switch (value) { - case MethodParameterValue methodParameterValue: { - if (methodParameterValue.SourceContext is MethodDefinition method) - return DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (DiagnosticUtilities.GetMethodParameterFromIndex (method, methodParameterValue.ParameterIndex)); - - return $"parameter #{methodParameterValue.ParameterIndex} of method '{methodParameterValue.SourceContext}'"; - } - - case MethodReturnValue methodReturnValue: { - if (methodReturnValue.SourceContext is MethodDefinition method) { - return DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (method.MethodReturnType); - } - - return "method return value"; - } - - case LoadFieldValue loadFieldValue: - return DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (loadFieldValue.Field); - - case SystemTypeForGenericParameterValue genericParameterValue: - return DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (genericParameterValue.GenericParameter); - - default: - return $"value from unknown source"; - } - } - static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (BindingFlags bindingFlags) => (bindingFlags.HasFlag (BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicNestedTypes : DynamicallyAccessedMemberTypes.None) | (bindingFlags.HasFlag (BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None); @@ -1567,4 +1748,4 @@ static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindi (bindingFlags.HasFlag (BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicEvents : DynamicallyAccessedMemberTypes.None) | (bindingFlags.HasFlag (BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None); } -} \ No newline at end of file +} diff --git a/src/linker/Linker.Dataflow/ReflectionPatternContext.cs b/src/linker/Linker.Dataflow/ReflectionPatternContext.cs index fa14997fa2f5..75c7e22f47fb 100644 --- a/src/linker/Linker.Dataflow/ReflectionPatternContext.cs +++ b/src/linker/Linker.Dataflow/ReflectionPatternContext.cs @@ -65,8 +65,7 @@ public void RecordHandledPattern () #endif } - public void RecordRecognizedPattern (T accessedItem, Action mark) - where T : IMemberDefinition + public void RecordRecognizedPattern (IMemberDefinition accessedItem, Action mark) { #if DEBUG if (!_patternAnalysisAttempted) @@ -81,7 +80,7 @@ public void RecordRecognizedPattern (T accessedItem, Action mark) _context.ReflectionPatternRecorder.RecognizedReflectionAccessPattern (Source, Instruction, accessedItem); } - public void RecordUnrecognizedPattern (string message) + public void RecordUnrecognizedPattern (int messageCode, string message) { #if DEBUG if (!_patternAnalysisAttempted) @@ -91,7 +90,7 @@ public void RecordUnrecognizedPattern (string message) #endif if (ReportingEnabled) - _context.ReflectionPatternRecorder.UnrecognizedReflectionAccessPattern (Source, Instruction, MemberWithRequirements, message); + _context.ReflectionPatternRecorder.UnrecognizedReflectionAccessPattern (Source, Instruction, MemberWithRequirements, message, messageCode); } public void Dispose () diff --git a/src/linker/Linker.Dataflow/ValueNode.cs b/src/linker/Linker.Dataflow/ValueNode.cs index 769f9c5253ae..7ca6c09fc6c2 100644 --- a/src/linker/Linker.Dataflow/ValueNode.cs +++ b/src/linker/Linker.Dataflow/ValueNode.cs @@ -11,6 +11,7 @@ using TypeDefinition = Mono.Cecil.TypeDefinition; using FieldDefinition = Mono.Cecil.FieldDefinition; using GenericParameter = Mono.Cecil.GenericParameter; +using Mono.Cecil; namespace Mono.Linker.Dataflow { @@ -609,7 +610,7 @@ protected override string NodeToString () } /// - /// This is a System.Type value which reprensents generic parameter (basically result of typeof(T)) + /// This is a System.Type value which represents generic parameter (basically result of typeof(T)) /// Its actual type is unknown, but it can have annotations. /// class SystemTypeForGenericParameterValue : LeafValueWithDynamicallyAccessedMemberNode @@ -619,6 +620,7 @@ public SystemTypeForGenericParameterValue (GenericParameter genericParameter, Dy Kind = ValueNodeKind.SystemTypeForGenericParameter; GenericParameter = genericParameter; DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes; + SourceContext = genericParameter; } public GenericParameter GenericParameter { get; } @@ -718,7 +720,7 @@ protected override string NodeToString () /// abstract class LeafValueWithDynamicallyAccessedMemberNode : LeafValueNode { - public object SourceContext { get; set; } + public IMetadataTokenProvider SourceContext { get; protected set; } /// /// The bitfield of dynamically accessed member types the node guarantees @@ -731,11 +733,12 @@ abstract class LeafValueWithDynamicallyAccessedMemberNode : LeafValueNode /// class MethodParameterValue : LeafValueWithDynamicallyAccessedMemberNode { - public MethodParameterValue (int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + public MethodParameterValue (int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes, IMetadataTokenProvider sourceContext) { Kind = ValueNodeKind.MethodParameter; ParameterIndex = parameterIndex; DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes; + SourceContext = sourceContext; } public int ParameterIndex { get; } @@ -767,10 +770,11 @@ protected override string NodeToString () /// class AnnotatedStringValue : LeafValueWithDynamicallyAccessedMemberNode { - public AnnotatedStringValue (DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + public AnnotatedStringValue (IMetadataTokenProvider sourceContext, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) { Kind = ValueNodeKind.AnnotatedString; DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes; + SourceContext = sourceContext; } public override bool Equals (ValueNode other) @@ -800,10 +804,11 @@ protected override string NodeToString () /// class MethodReturnValue : LeafValueWithDynamicallyAccessedMemberNode { - public MethodReturnValue (DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) + public MethodReturnValue (MethodReturnType methodReturnType, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) { Kind = ValueNodeKind.MethodReturn; DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes; + SourceContext = methodReturnType; } public override bool Equals (ValueNode other) @@ -1045,6 +1050,7 @@ public LoadFieldValue (FieldDefinition fieldToLoad, DynamicallyAccessedMemberTyp Kind = ValueNodeKind.LoadField; Field = fieldToLoad; DynamicallyAccessedMemberTypes = dynamicallyAccessedMemberTypes; + SourceContext = fieldToLoad; } public FieldDefinition Field { get; private set; } diff --git a/src/linker/Linker.Steps/BodySubstituterStep.cs b/src/linker/Linker.Steps/BodySubstituterStep.cs index ff3f191a3f76..773af56f605b 100644 --- a/src/linker/Linker.Steps/BodySubstituterStep.cs +++ b/src/linker/Linker.Steps/BodySubstituterStep.cs @@ -74,7 +74,7 @@ void ProcessMethod (TypeDefinition type, XPathNodeIterator iterator) MethodDefinition method = FindMethod (type, signature); if (method == null) { - Context.LogWarning ($"Could not find method '{signature}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2009, _xmlDocumentLocation); + Context.LogWarning ($"Could not find method '{signature}' on type '{type.GetDisplayName ()}'", 2009, _xmlDocumentLocation); return; } @@ -110,22 +110,22 @@ void ProcessField (TypeDefinition type, XPathNodeIterator iterator) var field = type.Fields.FirstOrDefault (f => f.Name == name); if (field == null) { - Context.LogWarning ($"Could not find field '{name}' in type '{type.GetDisplayName ()}' specified in { _xmlDocumentLocation}", 2012, _xmlDocumentLocation); + Context.LogWarning ($"Could not find field '{name}' on type '{type.GetDisplayName ()}'", 2012, _xmlDocumentLocation); return; } if (!field.IsStatic || field.IsLiteral) { - Context.LogWarning ($"Substituted field '{name}' needs to be static field.", 2013, _xmlDocumentLocation); + Context.LogWarning ($"Substituted field '{field.GetDisplayName ()}' needs to be static field.", 2013, _xmlDocumentLocation); return; } string value = GetAttribute (iterator.Current, "value"); if (string.IsNullOrEmpty (value)) { - Context.LogWarning ($"Missing 'value' attribute for field '{field}'.", 2014, _xmlDocumentLocation); + Context.LogWarning ($"Missing 'value' attribute for field '{field.GetDisplayName ()}'.", 2014, _xmlDocumentLocation); return; } if (!TryConvertValue (value, field.FieldType, out object res)) { - Context.LogWarning ($"Invalid value for '{field}': '{value}'.", 2015, _xmlDocumentLocation); + Context.LogWarning ($"Invalid value '{value}' for '{field.GetDisplayName ()}'.", 2015, _xmlDocumentLocation); return; } @@ -153,7 +153,7 @@ void ProcessResources (AssemblyDefinition assembly, XPathNodeIterator iterator) string action = GetAttribute (nav, "action"); if (action != "remove") { - Context.LogWarning ($"Invalid 'action' attribute for resource '{name}'.", 2039, _xmlDocumentLocation); + Context.LogWarning ($"Invalid value '{action}' for attribute 'action' for resource '{name}'.", 2039, _xmlDocumentLocation); continue; } diff --git a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs index 2c625f65abf7..97ca882a9bcb 100644 --- a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs +++ b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs @@ -59,7 +59,7 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) if (!IsPreserveDependencyAttribute (ca.AttributeType)) continue; #if FEATURE_ILLINK - Context.LogWarning ($"PreserveDependencyAttribute is deprecated. Use DynamicDependencyAttribute instead.", 2033, member); + Context.LogWarning ($"'PreserveDependencyAttribute' is deprecated. Use 'DynamicDependencyAttribute' instead.", 2033, member); #endif if (ca.ConstructorArguments.Count != 3) continue; @@ -82,7 +82,7 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) var assembly = Context.Resolve (new AssemblyNameReference (dynamicDependency.AssemblyName, new Version ())); if (assembly == null) { - Context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{member}'", 2035, member); + Context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in 'DynamicDependencyAttribute'", 2035, member); continue; } diff --git a/src/linker/Linker.Steps/LinkAttributesStep.cs b/src/linker/Linker.Steps/LinkAttributesStep.cs index d30fc60fe41f..d694ef3e927d 100644 --- a/src/linker/Linker.Steps/LinkAttributesStep.cs +++ b/src/linker/Linker.Steps/LinkAttributesStep.cs @@ -40,7 +40,7 @@ IEnumerable ProcessAttributes (XPathNavigator nav, ICustomAttri string attributeFullName = GetFullName (iterator.Current); if (attributeFullName == string.Empty) { - Context.LogWarning ($"Attribute element does not contain attribute 'fullname'", 2029, _xmlDocumentLocation); + Context.LogWarning ($"'attribute' element does not contain attribute 'fullname' or it's empty", 2029, _xmlDocumentLocation); continue; } @@ -57,10 +57,14 @@ IEnumerable ProcessAttributes (XPathNavigator nav, ICustomAttri CustomAttribute CreateCustomAttribute (XPathNodeIterator iterator, TypeDefinition attributeType) { - string[] attributeArguments = (GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty))).ToArray (); - MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == attributeArguments.Length); + string[] attributeArguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)).ToArray (); + var attributeArgumentCount = attributeArguments == null ? 0 : attributeArguments.Length; + MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == attributeArgumentCount); if (constructor == null) { - Context.LogWarning ($"Could not find a constructor for type '{attributeType}' that receives '{attributeArguments.Length}' arguments as parameter", 2022, _xmlDocumentLocation); + Context.LogWarning ( + $"Could not find a constructor for type '{attributeType}' that has '{attributeArgumentCount}' arguments", + 2022, + _xmlDocumentLocation); return null; } @@ -117,7 +121,10 @@ List ProcessAttributeArguments (MethodDefinition attrib object argValue; TypeDefinition parameterType = attributeConstructor.Parameters[i].ParameterType.Resolve (); if (!TryConvertValue (arguments[i], parameterType, out argValue)) { - Context.LogWarning ($"Invalid argument value '{arguments[i]}' for attribute '{attributeConstructor.DeclaringType.GetDisplayName ()}'", 2054, _xmlDocumentLocation); + Context.LogWarning ( + $"Invalid argument value '{arguments[i]}' for parameter type '{parameterType.GetDisplayName ()}' of attribute '{attributeConstructor.DeclaringType.GetDisplayName ()}'", + 2054, + _xmlDocumentLocation); return null; } @@ -154,8 +161,13 @@ bool GetAttributeType (XPathNodeIterator iterator, string attributeFullName, out AssemblyDefinition assembly; try { assembly = GetAssembly (Context, AssemblyNameReference.Parse (assemblyName)); + if (assembly == null) { + Context.LogWarning ($"Could not resolve assembly '{assemblyName}' for attribute '{attributeFullName}'", 2030, _xmlDocumentLocation); + attributeType = default; + return false; + } } catch (Exception) { - Context.LogWarning ($"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in '{_xmlDocumentLocation}'", 2030, _xmlDocumentLocation); + Context.LogWarning ($"Could not resolve assembly '{assemblyName}' for attribute '{attributeFullName}'", 2030, _xmlDocumentLocation); attributeType = default; return false; } @@ -242,7 +254,9 @@ void ProcessParameters (MethodDefinition method, XPathNavigator nav) foreach (ParameterDefinition parameter in method.Parameters) { if (paramName == parameter.Name) { if (Context.CustomAttributes.HasCustomAttributes (parameter)) - Context.LogWarning ($"There are duplicate parameter names for '{paramName}' inside '{method.GetDisplayName ()}' in '{_xmlDocumentLocation}'", 2024, _xmlDocumentLocation); + Context.LogWarning ( + $"More than one value specified for parameter '{paramName}' of method '{method.GetDisplayName ()}'", + 2024, _xmlDocumentLocation); Context.CustomAttributes.AddCustomAttributes (parameter, attributes); break; } @@ -262,7 +276,9 @@ void ProcessReturnParameters (MethodDefinition method, XPathNavigator nav) if (attributes.Count () > 0) Context.CustomAttributes.AddCustomAttributes (method.MethodReturnType, attributes); } else { - Context.LogWarning ($"There is more than one return parameter specified for '{method.GetDisplayName ()}' in '{_xmlDocumentLocation}'", 2023, _xmlDocumentLocation); + Context.LogWarning ( + $"There is more than one 'return' child element specified for method '{method.GetDisplayName ()}'", + 2023, _xmlDocumentLocation); } } } @@ -324,7 +340,9 @@ protected override void ProcessEvent (TypeDefinition type, EventDefinition @even protected override AssemblyDefinition GetAssembly (LinkContext context, AssemblyNameReference assemblyName) { var assembly = context.Resolve (assemblyName); - ProcessReferences (assembly); + if (assembly != null) + ProcessReferences (assembly); + return assembly; } } diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 018d3f8226a8..6fafac1023fd 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -615,7 +615,7 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, IMemberDefiniti if (dynamicDependency.AssemblyName != null) { assembly = _context.GetLoadedAssembly (dynamicDependency.AssemblyName); if (assembly == null) { - _context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", 2035, context); + _context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in 'DynamicDependencyAttribute'", 2035, context); return; } } else { @@ -627,19 +627,19 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, IMemberDefiniti if (dynamicDependency.TypeName is string typeName) { type = DocumentationSignatureParser.GetTypeByDocumentationSignature (assembly, typeName); if (type == null) { - _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", 2036, context); + _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute", 2036, context); return; } } else if (dynamicDependency.Type is TypeReference typeReference) { type = typeReference.Resolve (); if (type == null) { - _context.LogWarning ($"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", 2036, context); + _context.LogWarning ($"Unresolved type '{typeReference}' in DynamicDependencyAtribute", 2036, context); return; } } else { type = context.DeclaringType.Resolve (); if (type == null) { - _context.LogWarning ($"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", 2036, context); + _context.LogWarning ($"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute", 2036, context); return; } } @@ -724,7 +724,7 @@ protected virtual void MarkUserDependency (MemberReference context, CustomAttrib assembly = _context.GetLoadedAssembly (assemblyName); if (assembly == null) { _context.LogWarning ( - $"Could not resolve '{assemblyName}' assembly dependency specified in a `PreserveDependency` attribute that targets method '{context.GetDisplayName ()}'", 2003, context.Resolve ()); + $"Could not resolve dependency assembly '{assemblyName}' specified in a 'PreserveDependency' attribute", 2003, context.Resolve ()); return; } } else { @@ -737,7 +737,7 @@ protected virtual void MarkUserDependency (MemberReference context, CustomAttrib if (td == null) { _context.LogWarning ( - $"Could not resolve '{typeName}' type dependency specified in a `PreserveDependency` attribute that targets method '{context.GetDisplayName ()}'", 2004, context.Resolve ()); + $"Could not resolve dependency type '{typeName}' specified in a `PreserveDependency` attribute", 2004, context.Resolve ()); return; } } else { @@ -771,7 +771,7 @@ protected virtual void MarkUserDependency (MemberReference context, CustomAttrib return; _context.LogWarning ( - $"Could not resolve dependency member '{member}' declared in type '{td.GetDisplayName ()}' specified in a `PreserveDependency` attribute that targets method '{context.GetDisplayName ()}'", 2005, td); + $"Could not resolve dependency member '{member}' declared in type '{td.GetDisplayName ()}' specified in a `PreserveDependency` attribute", 2005, context.Resolve ()); } bool MarkDependencyMethod (TypeDefinition type, string name, string[] signature, in DependencyInfo reason, IMemberDefinition sourceLocationMember) @@ -1418,13 +1418,16 @@ internal protected virtual TypeDefinition MarkType (TypeReference reference, Dep if (_context.Annotations.HasLinkerAttribute (type)) { // Don't warn about references from the removed attribute itself (for example the .ctor on the attribute // will call MarkType on the attribute type itself). - // If for some reason we do keep the attribute type (could be because of previous reference which would cause 2045 + // If for some reason we do keep the attribute type (could be because of previous reference which would cause IL2045 // or because of a copy assembly with a reference and so on) then we should not spam the warnings due to the type itself. if (sourceLocationMember.DeclaringType != type) - _context.LogWarning ($"Custom Attribute {type.GetDisplayName ()} is being referenced in code but the linker was " + + _context.LogWarning ( + $"Attribute '{type.GetDisplayName ()}' is being referenced in code but the linker was " + $"instructed to remove all instances of this attribute. If the attribute instances are necessary make sure to " + - $"either remove the linker attribute XML portion which removes the attribute instances, or to override this use " + - $"the linker XML descriptor to keep the attribute type (which in turn keeps all of its instances).", 2045, sourceLocationMember); + $"either remove the linker attribute XML portion which removes the attribute instances, " + + $"or override the removal by using the linker XML descriptor to keep the attribute type " + + $"(which in turn keeps all of its instances).", + 2045, sourceLocationMember, subcategory: MessageSubCategory.TrimAnalysis); } if (CheckProcessed (type)) diff --git a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs index d6e25b60c518..264bd821b2f7 100644 --- a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs +++ b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs @@ -89,7 +89,7 @@ protected virtual void ProcessAssemblies (XPathNodeIterator iterator) AssemblyDefinition assembly = GetAssembly (Context, name); if (assembly == null) { - Context.LogWarning ($"Could not resolve assembly '{GetAssemblyName (iterator.Current).Name}' specified in {_xmlDocumentLocation}", 2007, _xmlDocumentLocation); + Context.LogWarning ($"Could not resolve assembly '{name.Name}'", 2007, _xmlDocumentLocation); continue; } @@ -132,7 +132,7 @@ protected virtual void ProcessTypes (AssemblyDefinition assembly, XPathNodeItera if (type == null) { if (warnOnUnresolvedTypes) - Context.LogWarning ($"Could not resolve type '{fullname}' specified in {_xmlDocumentLocation}", 2008, _xmlDocumentLocation); + Context.LogWarning ($"Could not resolve type '{fullname}'", 2008, _xmlDocumentLocation); continue; } @@ -207,7 +207,7 @@ protected virtual void ProcessField (TypeDefinition type, XPathNavigator nav) if (!String.IsNullOrEmpty (signature)) { FieldDefinition field = GetField (type, signature); if (field == null) { - Context.LogWarning ($"Could not find field '{signature}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2012, _xmlDocumentLocation); + Context.LogWarning ($"Could not find field '{signature}' on type '{type.GetDisplayName ()}'", 2012, _xmlDocumentLocation); return; } @@ -216,19 +216,18 @@ protected virtual void ProcessField (TypeDefinition type, XPathNavigator nav) string name = GetAttribute (nav, NameAttributeName); if (!String.IsNullOrEmpty (name)) { - if (!type.HasFields) - return; - bool foundMatch = false; - foreach (FieldDefinition field in type.Fields) { - if (field.Name == name) { - foundMatch = true; - ProcessField (type, field, nav); + if (type.HasFields) { + foreach (FieldDefinition field in type.Fields) { + if (field.Name == name) { + foundMatch = true; + ProcessField (type, field, nav); + } } } if (!foundMatch) { - Context.LogWarning ($"Could not find field '{name}' in type '{type.GetDisplayName ()}' specified in { _xmlDocumentLocation}", 2012, _xmlDocumentLocation); + Context.LogWarning ($"Could not find field '{name}' on type '{type.GetDisplayName ()}'", 2012, _xmlDocumentLocation); } } } @@ -266,7 +265,7 @@ protected virtual void ProcessMethod (TypeDefinition type, XPathNavigator nav, o if (!String.IsNullOrEmpty (signature)) { MethodDefinition method = GetMethod (type, signature); if (method == null) { - Context.LogWarning ($"Could not find method '{signature}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2009, _xmlDocumentLocation); + Context.LogWarning ($"Could not find method '{signature}' on type '{type.GetDisplayName ()}'", 2009, _xmlDocumentLocation); return; } @@ -275,19 +274,18 @@ protected virtual void ProcessMethod (TypeDefinition type, XPathNavigator nav, o string name = GetAttribute (nav, NameAttributeName); if (!String.IsNullOrEmpty (name)) { - if (!type.HasMethods) - return; - bool foundMatch = false; - foreach (MethodDefinition method in type.Methods) { - if (name == method.Name) { - foundMatch = true; - ProcessMethod (type, method, nav, customData); + if (type.HasMethods) { + foreach (MethodDefinition method in type.Methods) { + if (name == method.Name) { + foundMatch = true; + ProcessMethod (type, method, nav, customData); + } } } if (!foundMatch) { - Context.LogWarning ($"Could not find method '{name}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2009, _xmlDocumentLocation); + Context.LogWarning ($"Could not find method '{name}' on type '{type.GetDisplayName ()}'", 2009, _xmlDocumentLocation); } } } @@ -315,7 +313,7 @@ protected virtual void ProcessEvent (TypeDefinition type, XPathNavigator nav, ob if (!String.IsNullOrEmpty (signature)) { EventDefinition @event = GetEvent (type, signature); if (@event == null) { - Context.LogWarning ($"Could not find event '{signature}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2016, _xmlDocumentLocation); + Context.LogWarning ($"Could not find event '{signature}' on type '{type.GetDisplayName ()}'", 2016, _xmlDocumentLocation); return; } @@ -324,9 +322,6 @@ protected virtual void ProcessEvent (TypeDefinition type, XPathNavigator nav, ob string name = GetAttribute (nav, NameAttributeName); if (!String.IsNullOrEmpty (name)) { - if (!type.HasEvents) - return; - bool foundMatch = false; foreach (EventDefinition @event in type.Events) { if (@event.Name == name) { @@ -336,7 +331,7 @@ protected virtual void ProcessEvent (TypeDefinition type, XPathNavigator nav, ob } if (!foundMatch) { - Context.LogWarning ($"Could not find event '{name}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2016, _xmlDocumentLocation); + Context.LogWarning ($"Could not find event '{name}' on type '{type.GetDisplayName ()}'", 2016, _xmlDocumentLocation); } } } @@ -374,7 +369,7 @@ protected virtual void ProcessProperty (TypeDefinition type, XPathNavigator nav, if (!String.IsNullOrEmpty (signature)) { PropertyDefinition property = GetProperty (type, signature); if (property == null) { - Context.LogWarning ($"Could not find property '{signature}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2017, _xmlDocumentLocation); + Context.LogWarning ($"Could not find property '{signature}' on type '{type.GetDisplayName ()}'", 2017, _xmlDocumentLocation); return; } @@ -383,9 +378,6 @@ protected virtual void ProcessProperty (TypeDefinition type, XPathNavigator nav, string name = GetAttribute (nav, NameAttributeName); if (!String.IsNullOrEmpty (name)) { - if (!type.HasProperties) - return; - bool foundMatch = false; foreach (PropertyDefinition property in type.Properties) { if (property.Name == name) { @@ -395,7 +387,7 @@ protected virtual void ProcessProperty (TypeDefinition type, XPathNavigator nav, } if (!foundMatch) { - Context.LogWarning ($"Could not find property '{name}' in type '{type.GetDisplayName ()}' specified in {_xmlDocumentLocation}", 2017, _xmlDocumentLocation); + Context.LogWarning ($"Could not find property '{name}' on type '{type.GetDisplayName ()}'", 2017, _xmlDocumentLocation); } } } diff --git a/src/linker/Linker.Steps/ResolveFromXmlStep.cs b/src/linker/Linker.Steps/ResolveFromXmlStep.cs index 209f0daf9a39..d202c8ba273c 100644 --- a/src/linker/Linker.Steps/ResolveFromXmlStep.cs +++ b/src/linker/Linker.Steps/ResolveFromXmlStep.cs @@ -101,7 +101,7 @@ void ProcessNamespaces (AssemblyDefinition assembly, XPathNodeIterator iterator) } if (!foundMatch) { - Context.LogWarning ($"Could not find any type in namespace '{fullname}' specified in '{_xmlDocumentLocation}'", 2044, _xmlDocumentLocation); + Context.LogWarning ($"Could not find any type in namespace '{fullname}'", 2044, _xmlDocumentLocation); } } } @@ -183,7 +183,7 @@ protected override void ProcessField (TypeDefinition type, XPathNavigator nav) protected override void ProcessField (TypeDefinition type, FieldDefinition field, XPathNavigator nav) { if (Annotations.IsMarked (field)) - Context.LogWarning ($"Duplicate preserve of '{field.FullName}' in '{_xmlDocumentLocation}'", 2025, _xmlDocumentLocation); + Context.LogWarning ($"Duplicate preserve of '{field.FullName}'", 2025, _xmlDocumentLocation); Context.Annotations.Mark (field, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation)); } @@ -201,7 +201,7 @@ protected override void ProcessMethod (TypeDefinition type, XPathNavigator nav, protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object customData) { if (Annotations.IsMarked (method)) - Context.LogWarning ($"Duplicate preserve of '{method.GetDisplayName ()}' in '{_xmlDocumentLocation}'", 2025, _xmlDocumentLocation); + Context.LogWarning ($"Duplicate preserve of '{method.GetDisplayName ()}'", 2025, _xmlDocumentLocation); Annotations.Mark (method, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation)); Annotations.MarkIndirectlyCalledMethod (method); @@ -266,7 +266,7 @@ protected override void ProcessEvent (TypeDefinition type, XPathNavigator nav, o protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object customData) { if (Annotations.IsMarked (@event)) - Context.LogWarning ($"Duplicate preserve of '{@event.FullName}' in '{_xmlDocumentLocation}'", 2025, _xmlDocumentLocation); + Context.LogWarning ($"Duplicate preserve of '{@event.FullName}'", 2025, _xmlDocumentLocation); Annotations.Mark (@event, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation)); @@ -290,7 +290,7 @@ protected override void ProcessProperty (TypeDefinition type, PropertyDefinition string[] accessors = fromSignature ? GetAccessors (nav) : _accessorsAll; if (Annotations.IsMarked (property)) - Context.LogWarning ($"Duplicate preserve of '{property.FullName}' in '{_xmlDocumentLocation}'", 2025, _xmlDocumentLocation); + Context.LogWarning ($"Duplicate preserve of '{property.FullName}'", 2025, _xmlDocumentLocation); Annotations.Mark (property, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation)); @@ -308,7 +308,7 @@ void ProcessPropertyAccessors (TypeDefinition type, PropertyDefinition property, if (property.GetMethod != null && Array.IndexOf (accessors, "get") >= 0) ProcessMethod (type, property.GetMethod, null, customData); else if (property.GetMethod == null) - Context.LogWarning ($"Could not find the get accessor of property '{property.Name}' in type '{type.FullName}' specified in {_xmlDocumentLocation}", 2018, _xmlDocumentLocation); + Context.LogWarning ($"Could not find the get accessor of property '{property.Name}' on type '{type.FullName}'", 2018, _xmlDocumentLocation); if (property.SetMethod != null && Array.IndexOf (accessors, "set") >= 0) ProcessMethod (type, property.SetMethod, null, customData); @@ -319,7 +319,9 @@ void ProcessPropertyAccessors (TypeDefinition type, PropertyDefinition property, protected override AssemblyDefinition GetAssembly (LinkContext context, AssemblyNameReference assemblyName) { var assembly = context.Resolve (assemblyName); - ProcessReferences (assembly); + if (assembly != null) + ProcessReferences (assembly); + return assembly; } diff --git a/src/linker/Linker.Steps/ValidateVirtualMethodAnnotationsStep.cs b/src/linker/Linker.Steps/ValidateVirtualMethodAnnotationsStep.cs index da71eb5a5ec6..66bf4b2db66e 100644 --- a/src/linker/Linker.Steps/ValidateVirtualMethodAnnotationsStep.cs +++ b/src/linker/Linker.Steps/ValidateVirtualMethodAnnotationsStep.cs @@ -43,10 +43,9 @@ void ValidateMethodRequiresUnreferencedCodeAreSame (MethodDefinition method, Met if (annotations.HasLinkerAttribute (method) != annotations.HasLinkerAttribute (baseMethod)) Context.LogWarning ( - $"Presence of RequiresUnreferencedCodeAttribute on method '{method.GetDisplayName ()}' doesn't match overridden method '{baseMethod.GetDisplayName ()}'. " + - $"All overridden methods must have RequiresUnreferencedCodeAttribute.", - 2046, - method); + $"Presence of 'RequiresUnreferencedCodeAttribute' on method '{method.GetDisplayName ()}' doesn't match overridden method '{baseMethod.GetDisplayName ()}'. " + + $"All overridden methods must have 'RequiresUnreferencedCodeAttribute'.", + 2046, method, subcategory: MessageSubCategory.TrimAnalysis); } } } diff --git a/src/linker/Linker/Annotations.cs b/src/linker/Linker/Annotations.cs index e308003d1f70..5788c5a70fa3 100644 --- a/src/linker/Linker/Annotations.cs +++ b/src/linker/Linker/Annotations.cs @@ -500,10 +500,9 @@ public bool TryGetLinkerAttribute (IMemberDefinition member, out T attribute) { var attributes = GetLinkerAttributes (member); if (attributes.Count () > 1) { - context.LogWarning ($"Attribute '{typeof (T).FullName}' should only be used once on '{member}'.", 2027, member); + context.LogWarning ($"Attribute '{typeof (T).FullName}' should only be used once on '{((member is MemberReference memberRef) ? memberRef.GetDisplayName () : member.FullName)}'.", 2027, member); } - Debug.Assert (attributes.Count () <= 1); attribute = attributes.FirstOrDefault (); return attribute != null; } diff --git a/src/linker/Linker/DynamicDependency.cs b/src/linker/Linker/DynamicDependency.cs index 73e717f574b0..2d162e8b6e7c 100644 --- a/src/linker/Linker/DynamicDependency.cs +++ b/src/linker/Linker/DynamicDependency.cs @@ -75,7 +75,7 @@ public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typ if (dynamicDependency != null) return dynamicDependency; - context.LogWarning ($"Invalid DynamicDependencyAttribute on '{member}'", 2030, member); + context.LogWarning ($"The 'DynamicDependencyAttribute' could not be analyzed", 2034, member); return null; } diff --git a/src/linker/Linker/IReflectionPatternRecorder.cs b/src/linker/Linker/IReflectionPatternRecorder.cs index 1adc07ca886e..089e6b635757 100644 --- a/src/linker/Linker/IReflectionPatternRecorder.cs +++ b/src/linker/Linker/IReflectionPatternRecorder.cs @@ -60,8 +60,9 @@ public interface IReflectionPatternRecorder /// The item accessed through reflection. This can be one of: /// TypeDefinition, MethodDefinition, PropertyDefinition, FieldDefinition, EventDefinition, InterfaceImplementation. /// Humanly readable message describing what failed during the pattern recognition. + /// Message code to use when reporting the unrecognized pattern as a warning. /// This effectively means that there's a potential hole in the linker marking - some items which are accessed only through /// reflection may not be marked correctly and thus may fail at runtime. - void UnrecognizedReflectionAccessPattern (IMemberDefinition source, Instruction sourceInstruction, IMetadataTokenProvider accessedItem, string message); + void UnrecognizedReflectionAccessPattern (IMemberDefinition source, Instruction sourceInstruction, IMetadataTokenProvider accessedItem, string message, int messageCode); } } diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index 9c5cbe992838..9cca03e18a33 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -84,7 +84,9 @@ static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, return new RequiresUnreferencedCodeAttribute (message) { Url = url }; } - context.LogWarning ($"Attribute '{typeof (RequiresUnreferencedCodeAttribute).FullName}' on '{method.GetDisplayName ()}' doesn't have a required constructor argument.", 2028, method); + context.LogWarning ( + $"Attribute '{typeof (RequiresUnreferencedCodeAttribute).FullName}' doesn't have the required number of parameters specified", + 2028, method); return null; } } diff --git a/src/linker/Linker/LoggingReflectionPatternRecorder.cs b/src/linker/Linker/LoggingReflectionPatternRecorder.cs index cddfab980140..375b75caaf44 100644 --- a/src/linker/Linker/LoggingReflectionPatternRecorder.cs +++ b/src/linker/Linker/LoggingReflectionPatternRecorder.cs @@ -42,10 +42,10 @@ public void RecognizedReflectionAccessPattern (IMemberDefinition source, Instruc // Do nothing - there's no logging for successfully recognized patterns } - public void UnrecognizedReflectionAccessPattern (IMemberDefinition source, Instruction sourceInstruction, IMetadataTokenProvider accessedItem, string message) + public void UnrecognizedReflectionAccessPattern (IMemberDefinition source, Instruction sourceInstruction, IMetadataTokenProvider accessedItem, string message, int messageCode) { var origin = new MessageOrigin (source, sourceInstruction?.Offset); - _context.LogWarning (message, 2006, origin, MessageSubCategory.TrimAnalysis); + _context.LogWarning (message, messageCode, origin, MessageSubCategory.TrimAnalysis); } } } diff --git a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs index 42c52f12ff06..05e061b991c6 100644 --- a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs +++ b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs @@ -305,13 +305,13 @@ public void TestWarn (string warnArg, WarnVersion expectedVersion) #nullable enable [Theory] [InlineData (true, null, null, new uint[] { }, new uint[] { })] - [InlineData (false, "IL1001,IL####,IL2000,IL2021,IL2022", null, - new uint[] { 2021, 2022 }, new uint[] { })] + [InlineData (false, "IL1001,IL####,IL2000,IL2054,IL2022", null, + new uint[] { 2054, 2022 }, new uint[] { })] [InlineData (false, "IL2023,IL6000;IL5042 IL2040", "IL4000,IL4001;IL4002 IL4003", new uint[] { 2023, 2040, 5042, 6000 }, new uint[] { 4000, 4001, 4002, 4003 })] [InlineData (false, "IL3000;IL3000;ABCD", "IL2005 il3000 IL2005", new uint[] { 3000 }, new uint[] { 2005 })] - [InlineData (true, null, "IL2006", new uint[] { }, new uint[] { 2006 })] + [InlineData (true, null, "IL2067", new uint[] { }, new uint[] { 2067 })] [InlineData (true, "IL2001", "IL2001", new uint[] { }, new uint[] { 2001 })] public void TestWarningsAsErrors (bool treatWarningsAsErrors, string? warningsAsErrors, string? warningsNotAsErrors, uint[] warnAsError, uint[] warnNotAsError) { diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs new file mode 100644 index 000000000000..1be89f73a3ad --- /dev/null +++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/ExpectedWarningAttribute.cs @@ -0,0 +1,19 @@ +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Assertions +{ + [AttributeUsage ( + AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Field, + AllowMultiple = true, + Inherited = false)] + public class ExpectedWarningAttribute : EnableLoggerAttribute + { + public ExpectedWarningAttribute (string warningCode, params string[] messageContains) + { + } + + public string FileName { get; set; } + public int SourceLine { get; set; } + public int SourceColumn { get; set; } + } +} diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs index 567d225dfde0..edd943d0de1c 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs @@ -16,35 +16,24 @@ namespace Mono.Linker.Tests.Cases.Expectations.Assertions Inherited = false)] public class UnrecognizedReflectionAccessPatternAttribute : BaseExpectedLinkedBehaviorAttribute { - public UnrecognizedReflectionAccessPatternAttribute (Type reflectionMethodType, string reflectionMethodName, Type[] reflectionMethodParameters, - string message = null, + public UnrecognizedReflectionAccessPatternAttribute ( + Type reflectionMethodType, + string reflectionMethodName, + Type[] reflectionMethodParameters, + object message = null, + string messageCode = null, Type returnType = null) { - if (reflectionMethodType == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (reflectionMethodType)); - if (reflectionMethodName == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (reflectionMethodName)); - if (reflectionMethodParameters == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (reflectionMethodParameters)); - - if (message == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); } - public UnrecognizedReflectionAccessPatternAttribute (Type reflectionMethodType, string reflectionMethodName, + public UnrecognizedReflectionAccessPatternAttribute ( + Type reflectionMethodType, + string reflectionMethodName, string[] reflectionMethodParameters = null, - string message = null, + object message = null, + string messageCode = null, Type returnType = null) { - if (reflectionMethodType == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (reflectionMethodType)); - if (reflectionMethodName == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (reflectionMethodName)); - if (reflectionMethodParameters == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (reflectionMethodParameters)); - - if (message == null) - throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); } } } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs index 0de17059c31f..91435ae065b4 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs @@ -18,8 +18,8 @@ static void Main () TestConstructors (); } - [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequirePublicConstructors), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequireNonPublicConstructors), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequirePublicConstructors), new Type[] { typeof (string) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequireNonPublicConstructors), new Type[] { typeof (string) }, messageCode: "IL2072")] static void TestPublicParameterlessConstructor () { string type = GetTypeWithPublicParameterlessConstructor ().AssemblyQualifiedName; @@ -29,7 +29,7 @@ static void TestPublicParameterlessConstructor () RequireNothing (type); } - [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequireNonPublicConstructors), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequireNonPublicConstructors), new Type[] { typeof (string) }, messageCode: "IL2072")] static void TestPublicConstructors () { string type = GetTypeWithPublicConstructors ().AssemblyQualifiedName; @@ -39,8 +39,8 @@ static void TestPublicConstructors () RequireNothing (type); } - [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequirePublicConstructors), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (string) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (AssemblyQualifiedNameDataflow), nameof (RequirePublicConstructors), new Type[] { typeof (string) }, messageCode: "IL2072")] static void TestConstructors () { string type = GetTypeWithNonPublicConstructors ().AssemblyQualifiedName; diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs index 2775f82eaa57..abb12a5bfa4c 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs @@ -41,14 +41,14 @@ public static void Main () static Type s_typeWithPublicParameterlessConstructor; [Kept] - [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "System.Type&" })] + [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "System.Type&" }, messageCode: "IL2077")] public static void PassRefToField () { MethodWithRefParameter (ref s_typeWithPublicParameterlessConstructor); } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "System.Type&" })] + [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "System.Type&" }, messageCode: "IL2067")] public static void PassRefToParameter (Type parameter) { MethodWithRefParameter (ref parameter); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs index af0760d85bc8..9c1cd8ed8ead 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs @@ -18,7 +18,7 @@ public static void Main () static Type TypeWithPublicMethods; [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Type), "GetField", new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), "GetField", new Type[] { typeof (string) }, messageCode: "IL2080")] [DynamicDependency ("DynamicDependencyTo")] static void DynamicDependencyFrom () { @@ -26,7 +26,7 @@ static void DynamicDependencyFrom () } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Type), "GetProperty", new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), "GetProperty", new Type[] { typeof (string) }, messageCode: "IL2080")] static void DynamicDependencyTo () { _ = TypeWithPublicMethods.GetProperty ("p"); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs index ea3c8640e366..0fe6f810406c 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/EmptyArrayIntrinsicsDataFlow.cs @@ -19,21 +19,21 @@ static void Main () TestGetPublicParameterlessConstructorWithUnknownArray (); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string) }, messageCode: "IL2080")] static void TestGetPublicParameterlessConstructorWithEmptyTypes () { s_typeWithKeptPublicParameterlessConstructor.GetConstructor (Type.EmptyTypes); s_typeWithKeptPublicParameterlessConstructor.GetMethod ("Foo"); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string) }, messageCode: "IL2080")] static void TestGetPublicParameterlessConstructorWithArrayEmpty () { s_typeWithKeptPublicParameterlessConstructor.GetConstructor (Array.Empty ()); s_typeWithKeptPublicParameterlessConstructor.GetMethod ("Foo"); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (Type[]) }, messageCode: "IL2080")] static void TestGetPublicParameterlessConstructorWithUnknownArray () { s_typeWithKeptPublicParameterlessConstructor.GetConstructor (s_localEmptyArrayInvisibleToAnalysis); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs index 9cfcf4efdef6..21b96b9b82e8 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs @@ -30,6 +30,8 @@ public static void Main () instance.ReadFromStaticFieldOnADifferentClass (); instance.WriteToStaticFieldOnADifferentClass (); + + instance.WriteUnknownValue (); } [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] @@ -38,13 +40,11 @@ public static void Main () [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] static Type _staticTypeWithPublicParameterlessConstructor; + static Type _staticTypeWithoutRequirements; + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, - "The field 'System.Type Mono.Linker.Tests.Cases.DataFlow.FieldDataFlow::_typeWithPublicParameterlessConstructor' " + - "with dynamically accessed member kinds 'PublicParameterlessConstructor' is passed into " + - "the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.FieldDataFlow.RequirePublicConstructors(Type)' " + - "which requires dynamically accessed member kinds 'PublicConstructors'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicConstructors'.")] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + messageCode: "IL2077", message: new string[] { "_typeWithPublicParameterlessConstructor", "type", "RequirePublicConstructors(Type)" })] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] private void ReadFromInstanceField () { RequirePublicParameterlessConstructor (_typeWithPublicParameterlessConstructor); @@ -53,8 +53,12 @@ private void ReadFromInstanceField () RequireNothing (_typeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_typeWithPublicParameterlessConstructor))] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_typeWithPublicParameterlessConstructor))] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_typeWithPublicParameterlessConstructor), + messageCode: "IL2074", message: new string[] { + nameof (GetUnkownType), + nameof (_typeWithPublicParameterlessConstructor) + })] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_typeWithPublicParameterlessConstructor), messageCode: "IL2074")] private void WriteToInstanceField () { _typeWithPublicParameterlessConstructor = GetTypeWithPublicParameterlessConstructor (); @@ -63,8 +67,8 @@ private void WriteToInstanceField () _typeWithPublicParameterlessConstructor = GetUnkownType (); } - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] private void ReadFromInstanceFieldOnADifferentClass () { var store = new TypeStore (); @@ -75,8 +79,8 @@ private void ReadFromInstanceFieldOnADifferentClass () RequireNothing (store._typeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._typeWithPublicParameterlessConstructor))] - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._typeWithPublicParameterlessConstructor))] + [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._typeWithPublicParameterlessConstructor), messageCode: "IL2074")] + [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._typeWithPublicParameterlessConstructor), messageCode: "IL2074")] private void WriteToInstanceFieldOnADifferentClass () { var store = new TypeStore (); @@ -87,8 +91,8 @@ private void WriteToInstanceFieldOnADifferentClass () store._typeWithPublicParameterlessConstructor = GetUnkownType (); } - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] private void ReadFromStaticField () { RequirePublicParameterlessConstructor (_staticTypeWithPublicParameterlessConstructor); @@ -97,18 +101,24 @@ private void ReadFromStaticField () RequireNothing (_staticTypeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor))] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor))] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (_staticTypeWithPublicParameterlessConstructor), + messageCode: "IL2079", message: new string[] { + nameof(_staticTypeWithoutRequirements), + nameof(_staticTypeWithPublicParameterlessConstructor) + })] private void WriteToStaticField () { _staticTypeWithPublicParameterlessConstructor = GetTypeWithPublicParameterlessConstructor (); _staticTypeWithPublicParameterlessConstructor = GetTypeWithPublicConstructors (); _staticTypeWithPublicParameterlessConstructor = GetTypeWithNonPublicConstructors (); _staticTypeWithPublicParameterlessConstructor = GetUnkownType (); + _staticTypeWithPublicParameterlessConstructor = _staticTypeWithoutRequirements; } - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] + [UnrecognizedReflectionAccessPattern (typeof (FieldDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] private void ReadFromStaticFieldOnADifferentClass () { RequirePublicParameterlessConstructor (TypeStore._staticTypeWithPublicParameterlessConstructor); @@ -117,8 +127,8 @@ private void ReadFromStaticFieldOnADifferentClass () RequireNothing (TypeStore._staticTypeWithPublicParameterlessConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor))] - [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor))] + [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] + [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), messageCode: "IL2074")] private void WriteToStaticFieldOnADifferentClass () { TypeStore._staticTypeWithPublicParameterlessConstructor = GetTypeWithPublicParameterlessConstructor (); @@ -127,6 +137,14 @@ private void WriteToStaticFieldOnADifferentClass () TypeStore._staticTypeWithPublicParameterlessConstructor = GetUnkownType (); } + [UnrecognizedReflectionAccessPattern (typeof (TypeStore), nameof (TypeStore._staticTypeWithPublicParameterlessConstructor), messageCode: "IL2064", message: nameof (TypeStore._staticTypeWithPublicParameterlessConstructor))] + private void WriteUnknownValue () + { + var array = new object[1]; + array[0] = this.GetType (); + TypeStore._staticTypeWithPublicParameterlessConstructor = (Type) array[0]; + } + private static void RequirePublicParameterlessConstructor ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type) diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs index 2350c95d243c..e2d589f7e577 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs @@ -30,6 +30,9 @@ public static void Main () TestMakeGenericMethod (); TestNewConstraintSatisfiesParameterlessConstructor (); + + TestGenericParameterFlowsToField (); + TestGenericParameterFlowsToReturnValue (); } static void TestSingleGenericParameterOnType () @@ -41,22 +44,86 @@ static void TestSingleGenericParameterOnType () TypeRequiresNothingPassThrough.Test (); } + static void TestGenericParameterFlowsToField () + { + TypeRequiresPublicFields.TestFields (); + } + + static void TestGenericParameterFlowsToReturnValue () + { + _ = TypeRequiresPublicFields.ReturnRequiresPublicFields (); + _ = TypeRequiresPublicFields.ReturnRequiresPublicMethods (); + _ = TypeRequiresPublicFields.ReturnRequiresNothing (); + } + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + static Type FieldRequiresPublicFields; + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + static Type FieldRequiresPublicMethods; + + static Type FieldRequiresNothing; + class TypeRequiresPublicFields< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> { - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, + messageCode: "IL2087", message: new string[] { + nameof (T), + nameof (TypeRequiresPublicFields ), + nameof (RequiresPublicMethods) + })] public static void Test () { RequiresPublicFields (typeof (T)); RequiresPublicMethods (typeof (T)); RequiresNothing (typeof (T)); } + + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (FieldRequiresPublicMethods), + messageCode: "IL2089", message: new string[] { + nameof (T), + nameof (TypeRequiresPublicFields ), + nameof (FieldRequiresPublicMethods) + })] + public static void TestFields () + { + FieldRequiresPublicFields = typeof (T); + FieldRequiresPublicMethods = typeof (T); + FieldRequiresNothing = typeof (T); + } + + + [RecognizedReflectionAccessPattern] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + public static Type ReturnRequiresPublicFields () + { + return typeof (T); + } + + + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicFields<>), nameof (ReturnRequiresPublicMethods), new Type[] { }, returnType: typeof (Type), + messageCode: "IL2088", message: new string[] { + nameof (T), + nameof (TypeRequiresPublicFields), + nameof (ReturnRequiresPublicMethods) + })] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public static Type ReturnRequiresPublicMethods () + { + return typeof (T); + } + + public static Type ReturnRequiresNothing () + { + return typeof (T); + } } class TypeRequiresPublicMethods< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> { - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] public static void Test () { RequiresPublicFields (typeof (T)); @@ -67,8 +134,8 @@ public static void Test () class TypeRequiresNothing { - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, messageCode: "IL2087")] public static void Test () { RequiresPublicFields (typeof (T)); @@ -78,25 +145,26 @@ public static void Test () } class TypeRequiresPublicFieldsPassThrough< - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TSource> { [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", - message: "The generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeRequiresPublicFieldsPassThrough' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeRequiresPublicMethods' " + - "which requires dynamically accessed member kinds 'PublicMethods'. To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2091", message: new string[] { + nameof(TSource), + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeRequiresPublicFieldsPassThrough", + "T", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeRequiresPublicMethods" })] public static void Test () { - TypeRequiresPublicFields.Test (); - TypeRequiresPublicMethods.Test (); - TypeRequiresNothing.Test (); + TypeRequiresPublicFields.Test (); + TypeRequiresPublicMethods.Test (); + TypeRequiresNothing.Test (); } } class TypeRequiresNothingPassThrough { - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicFields<>), "T")] - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicFields<>), "T", messageCode: "IL2091")] + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] public static void Test () { TypeRequiresPublicFields.Test (); @@ -133,7 +201,7 @@ public static void TestMultiple () RequiresNothing (typeof (TNothing)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, messageCode: "IL2087")] public static void TestFields () { RequiresPublicFields (typeof (TFields)); @@ -141,7 +209,7 @@ public static void TestFields () RequiresNothing (typeof (TFields)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] public static void TestMethods () { RequiresPublicFields (typeof (TMethods)); @@ -157,8 +225,8 @@ public static void TestBoth () RequiresNothing (typeof (TBoth)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, messageCode: "IL2087")] public static void TestNothing () { RequiresPublicFields (typeof (TNothing)); @@ -188,7 +256,7 @@ class DerivedTypeWithInstantiatedGenericOnBase : GenericBaseTypeWithRequirements { } - [UnrecognizedReflectionAccessPattern (typeof (GenericBaseTypeWithRequirements<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (GenericBaseTypeWithRequirements<>), "T", messageCode: "IL2091")] class DerivedTypeWithOpenGenericOnBase : GenericBaseTypeWithRequirements { } @@ -215,7 +283,7 @@ class InterfaceImplementationTypeWithInstantiatedGenericOnBase : IGenericInterfa { } - [UnrecognizedReflectionAccessPattern (typeof (IGenericInterfaceTypeWithRequirements<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (IGenericInterfaceTypeWithRequirements<>), "T", messageCode: "IL2091")] class InterfaceImplementationTypeWithOpenGenericOnBase : IGenericInterfaceTypeWithRequirements { } @@ -239,11 +307,11 @@ public class InnerTypeWithNoAddedGenerics // The message is not ideal since we report the TRoot to come from RootTypeWithRequirements/InnerTypeWIthNoAddedGenerics // while it originates on RootTypeWithRequirements, but it's correct from IL's point of view. [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, - message: "The generic parameter 'TRoot' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.RootTypeWithRequirements.InnerTypeWithNoAddedGenerics' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.RequiresPublicMethods(Type)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2087", message: new string[] { + nameof(TRoot), + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.RootTypeWithRequirements.InnerTypeWithNoAddedGenerics", + "type", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.RequiresPublicMethods(Type)" })] public static void TestAccess () { RequiresPublicFields (typeof (TRoot)); @@ -281,7 +349,7 @@ class TypeGenericRequirementsOnMembers<[DynamicallyAccessedMembers (DynamicallyA [RecognizedReflectionAccessPattern] public TypeRequiresPublicFields PublicFieldsField; - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] public TypeRequiresPublicMethods PublicMethodsField; public TypeRequiresPublicFields PublicFieldsProperty { @@ -291,21 +359,21 @@ public TypeRequiresPublicFields PublicFieldsProperty { set; } public TypeRequiresPublicMethods PublicMethodsProperty { - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] get; - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] set; } [RecognizedReflectionAccessPattern] public void PublicFieldsMethodParameter (TypeRequiresPublicFields param) { } - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] public void PublicMethodsMethodParameter (TypeRequiresPublicMethods param) { } [RecognizedReflectionAccessPattern] public TypeRequiresPublicFields PublicFieldsMethodReturnValue () { return null; } - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] // Return value - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] // Compiler generated local variable + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] // Return value + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] // Compiler generated local variable public TypeRequiresPublicMethods PublicMethodsMethodReturnValue () { return null; } [RecognizedReflectionAccessPattern] @@ -313,7 +381,7 @@ public void PublicFieldsMethodLocalVariable () { TypeRequiresPublicFields t = null; } - [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T")] + [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] public void PublicMethodsMethodLocalVariable () { TypeRequiresPublicMethods t = null; @@ -347,7 +415,7 @@ class FullyInstantiatedOverPartiallyInstantiatedFields { } - [UnrecognizedReflectionAccessPattern (typeof (BaseForPartialInstantiation<,>), "TMethods")] + [UnrecognizedReflectionAccessPattern (typeof (BaseForPartialInstantiation<,>), "TMethods", messageCode: "IL2091")] class PartialyInstantiatedMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TOuter> : BaseForPartialInstantiation { @@ -368,7 +436,7 @@ static void TestSingleGenericParameterOnMethod () MethodRequiresNothingPassThrough (); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, messageCode: "IL2087")] static void MethodRequiresPublicFields< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> () { @@ -377,7 +445,7 @@ static void MethodRequiresPublicFields< RequiresNothing (typeof (T)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] static void MethodRequiresPublicMethods< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () { @@ -386,8 +454,8 @@ static void MethodRequiresPublicMethods< RequiresNothing (typeof (T)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, messageCode: "IL2087")] static void MethodRequiresNothing () { RequiresPublicFields (typeof (T)); @@ -395,7 +463,7 @@ static void MethodRequiresNothing () RequiresNothing (typeof (T)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "()::T")] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "()::T", messageCode: "IL2091")] static void MethodRequiresPublicFieldsPassThrough< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> () { @@ -404,8 +472,8 @@ static void MethodRequiresPublicFieldsPassThrough< MethodRequiresNothing (); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicFields) + "()::T")] - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "()::T")] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicFields) + "()::T", messageCode: "IL2091")] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "()::T", messageCode: "IL2091")] static void MethodRequiresNothingPassThrough () { MethodRequiresPublicFields (); @@ -478,10 +546,11 @@ class TypeWithInstantiatedGenericMethodViaGenericParameter<[DynamicallyAccessedM : BaseTypeWithGenericMethod, IInterfaceWithGenericMethod { [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "()::T", - message: "The generic parameter 'TInner' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter.StaticRequiresPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresPublicMethods()' which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2091", message: new string[] { + "TInner", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter.StaticRequiresPublicFields()", + "T", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresPublicMethods()" })] public static void StaticRequiresPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TInner> () { StaticRequiresPublicFields (); @@ -489,10 +558,11 @@ class TypeWithInstantiatedGenericMethodViaGenericParameter<[DynamicallyAccessedM } [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "()::T", - message: "The generic parameter 'TOuter' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresPublicMethods()' which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2091", message: new string[] { + "TOuter", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter", + "T", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresPublicMethods()" })] public static void StaticRequiresPublicFieldsNonGeneric () { StaticRequiresPublicFields (); @@ -506,20 +576,22 @@ public static void StaticPartialInstantiation () } [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams) + "()::TMethods", - message: "The generic parameter 'TOuter' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the generic parameter 'TMethods' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams()' " + - "which requires dynamically accessed member kinds 'PublicMethods'. To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2091", message: new string[] { + "TOuter", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter", + "TMethods", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams()" })] public static void StaticPartialInstantiationUnrecognized () { StaticRequiresMultipleGenericParams (); } [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "()::T", - message: "The generic parameter 'TInner' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter.InstanceRequiresPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.InstanceRequiresPublicMethods()' which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2091", message: new string[] { + "TInner", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter.InstanceRequiresPublicFields()", + "T", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.InstanceRequiresPublicMethods()" })] public void InstanceRequiresPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TInner> () { InstanceRequiresPublicFields (); @@ -527,10 +599,11 @@ public static void StaticPartialInstantiationUnrecognized () } [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "()::T", - message: "The generic parameter 'TOuter' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.InstanceRequiresPublicMethods()' which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2091", message: new string[] { + "TOuter", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter", + "T", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.BaseTypeWithGenericMethod.InstanceRequiresPublicMethods()" })] public void InstanceRequiresPublicFieldsNonGeneric () { InstanceRequiresPublicFields (); @@ -562,10 +635,11 @@ public void InstanceRequiresPublicFieldsNonGeneric () } [UnrecognizedReflectionAccessPattern (typeof (IInterfaceWithGenericMethod), nameof (IInterfaceWithGenericMethod.InterfaceRequiresPublicMethods) + "()::T", - message: "The generic parameter 'TOuter' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.IInterfaceWithGenericMethod.InterfaceRequiresPublicMethods()' " + - "which requires dynamically accessed member kinds 'PublicMethods'. To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2091", message: new string[] { + "TOuter", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter", + "T", + "Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.IInterfaceWithGenericMethod.InterfaceRequiresPublicMethods()" })] public void CallInterface () { IInterfaceWithGenericMethod interfaceInstance = (IInterfaceWithGenericMethod) this; @@ -601,7 +675,7 @@ static void MethodMultipleWithDifferentRequirements_TestMultiple< RequiresNothing (typeof (TNothing)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, messageCode: "IL2087")] static void MethodMultipleWithDifferentRequirements_TestFields< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TMethods, @@ -613,7 +687,7 @@ static void MethodMultipleWithDifferentRequirements_TestFields< RequiresNothing (typeof (TFields)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] static void MethodMultipleWithDifferentRequirements_TestMethods< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TMethods, @@ -636,8 +710,8 @@ static void MethodMultipleWithDifferentRequirements_TestBoth< RequiresNothing (typeof (TBoth)); } - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicFields), new Type[] { typeof (Type) }, messageCode: "IL2087")] + [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (RequiresPublicMethods), new Type[] { typeof (Type) }, messageCode: "IL2087")] static void MethodMultipleWithDifferentRequirements_TestNothing< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TMethods, @@ -689,7 +763,7 @@ static void TestMakeGenericTypeNullType () nullType.MakeGenericType (typeof (TestType)); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericTypeUnknownInput (Type inputType) { inputType.MakeGenericType (typeof (TestType)); @@ -705,7 +779,7 @@ class TypeMakeGenericNoArguments { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithRequirements () { // Currently this is not analyzable since we don't track array elements. @@ -713,14 +787,14 @@ static void TestMakeGenericWithRequirements () typeof (TypeMakeGenericWithPublicFieldsArgument<>).MakeGenericType (typeof (TestType)); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithRequirementsFromParam ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) { typeof (TypeMakeGenericWithPublicFieldsArgument<>).MakeGenericType (type); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithRequirementsFromGenericParam< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> () { @@ -747,7 +821,7 @@ class TypeMakeGenericWithNoRequirements { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, messageCode: "IL2055")] static void TestMakeGenericWithMultipleArgumentsWithRequirements () { typeof (TypeMakeGenericWithMultipleArgumentsWithRequirements<,>).MakeGenericType (typeof (TestType), typeof (TestType)); @@ -765,7 +839,7 @@ static void TestMakeGenericMethod () TestMakeGenericMethodWithNoRequirements (); } - [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, messageCode: "IL2060")] static void TestMakeGenericMethodWithRequirements () { typeof (GenericParameterDataFlow).GetMethod (nameof (MethodMakeGenericWithRequirements), BindingFlags.Static | BindingFlags.NonPublic) @@ -776,7 +850,7 @@ static void TestMakeGenericMethodWithRequirements () { } - [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) })] + [UnrecognizedReflectionAccessPattern (typeof (System.Reflection.MethodInfo), nameof (System.Reflection.MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, messageCode: "IL2060")] static void TestMakeGenericMethodWithNoRequirements () { typeof (GenericParameterDataFlow).GetMethod (nameof (MethodMakeGenericWithNoRequirements), BindingFlags.Static | BindingFlags.NonPublic) diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs index 050bc9d11383..14af1cfe3a24 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs @@ -34,8 +34,8 @@ public static void Main () // Type.GetType over two params } - [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] static void TestPublicParameterlessConstructor () { Type type = Type.GetType (GetStringTypeWithPublicParameterlessConstructor ()); @@ -45,7 +45,7 @@ static void TestPublicParameterlessConstructor () RequireNothing (type); } - [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] static void TestPublicConstructors () { Type type = Type.GetType (GetStringTypeWithPublicConstructors ()); @@ -55,8 +55,8 @@ static void TestPublicConstructors () RequireNothing (type); } - [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] static void TestConstructors () { Type type = Type.GetType (GetStringTypeWithNonPublicConstructors ()); @@ -66,13 +66,13 @@ static void TestConstructors () RequireNothing (type); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (GetType), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (GetType), new Type[] { typeof (string) }, messageCode: "IL2057")] static void TestUnknownType () { Type type = Type.GetType (GetStringUnkownType ()); } - [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] static void TestTypeNameFromParameter ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] string typeName) @@ -83,7 +83,7 @@ static void TestTypeNameFromParameter ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] static string _typeNameWithPublicParameterlessConstructor; - [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] static void TestTypeNameFromField () { RequirePublicConstructors (Type.GetType (_typeNameWithPublicParameterlessConstructor)); @@ -113,13 +113,9 @@ static void TestMultipleConstantValues () } [UnrecognizedReflectionAccessPattern (typeof (GetTypeDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, - "The method return value with dynamically accessed member kinds 'PublicParameterlessConstructor' is passed into " + - "the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.GetTypeDataFlow.RequireNonPublicConstructors(Type)' " + - "which requires dynamically accessed member kinds 'NonPublicConstructors'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'NonPublicConstructors'.")] + messageCode: "IL2072", message: "GetType")] [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetType), new Type[] { typeof (string) }, - "Reflection call 'System.Type.GetType(String)' inside 'Mono.Linker.Tests.Cases.DataFlow.GetTypeDataFlow.TestMultipleMixedValues()' " + - "was detected with unknown value for the type name.")] + messageCode: "IL2057", message: "System.Type.GetType(String)")] static void TestMultipleMixedValues () { string typeName = null; diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs index f864da9c4311..1cf63d79da58 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/LocalDataFlow.cs @@ -38,17 +38,15 @@ public static void Main () } [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)' " + - "which requires dynamically accessed member kinds 'PublicFields'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicFields'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)"})] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)"})] public static void TestBranchMergeGoto () { string str = GetWithPublicMethods (); @@ -62,17 +60,15 @@ public static void TestBranchMergeGoto () } [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)' " + - "which requires dynamically accessed member kinds 'PublicFields'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicFields'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)" })] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)" })] public static void TestBranchMergeIf () { string str = GetWithPublicMethods (); @@ -84,17 +80,15 @@ public static void TestBranchMergeIf () } [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)' " + - "which requires dynamically accessed member kinds 'PublicFields'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicFields'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)" })] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)" })] public static void TestBranchMergeIfElse () { string str = null; @@ -110,23 +104,20 @@ public static void TestBranchMergeIfElse () static int _switchOnField; [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequireNonPublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequireNonPublicMethods(String)' " + - "which requires dynamically accessed member kinds 'NonPublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'NonPublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequireNonPublicMethods(String)" })] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequireNonPublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequireNonPublicMethods(String)' " + - "which requires dynamically accessed member kinds 'NonPublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'NonPublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequireNonPublicMethods(String)" })] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequireNonPublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicConstructors()' " + - "with dynamically accessed member kinds 'PublicConstructors' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequireNonPublicMethods(String)' " + - "which requires dynamically accessed member kinds 'NonPublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'NonPublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicConstructors()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequireNonPublicMethods(String)" })] public static void TestBranchMergeSwitch () { string str = null; @@ -148,17 +139,15 @@ public static void TestBranchMergeSwitch () } [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)' " + - "which requires dynamically accessed member kinds 'PublicFields'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicFields'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)" })] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)" })] public static void TestBranchMergeTry () { string str = GetWithPublicMethods (); @@ -174,17 +163,15 @@ public static void TestBranchMergeTry () } [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)' " + - "which requires dynamically accessed member kinds 'PublicFields'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicFields'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)" })] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)" })] public static void TestBranchMergeCatch () { string str = GetWithPublicMethods (); @@ -199,17 +186,15 @@ public static void TestBranchMergeCatch () } [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)' " + - "which requires dynamically accessed member kinds 'PublicFields'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicFields'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicMethods()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicFields(String)" })] [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()' " + - "with dynamically accessed member kinds 'PublicFields' " + - "is passed into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + messageCode: "IL2072", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.GetWithPublicFields()", + "type", + "Mono.Linker.Tests.Cases.DataFlow.LocalDataFlow.RequirePublicMethods(String)" })] public static void TestBranchMergeFinally () { string str = GetWithPublicMethods (); @@ -224,7 +209,7 @@ public static void TestBranchMergeFinally () RequirePublicMethods (str); // warns for GetWithPublicFields } - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, messageCode: "IL2072")] public static void TestBranchGoto () { string str = GetWithPublicMethods (); @@ -236,7 +221,7 @@ public static void TestBranchGoto () return; } - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, messageCode: "IL2072")] public static void TestBranchIf () { string str = GetWithPublicMethods (); @@ -246,7 +231,7 @@ public static void TestBranchIf () } } - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, messageCode: "IL2072")] public static void TestBranchIfElse () { string str; @@ -261,12 +246,12 @@ public static void TestBranchIfElse () } } - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequireNonPublicMethods), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequireNonPublicMethods), new Type[] { typeof (string) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicMethods), new Type[] { typeof (string) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (string) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (string) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (string) }, messageCode: "IL2072")] public static void TestBranchSwitch () { string str = null; @@ -290,7 +275,7 @@ public static void TestBranchSwitch () } } - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, messageCode: "IL2072")] public static void TestBranchTry () { string str = GetWithPublicMethods (); @@ -304,7 +289,7 @@ public static void TestBranchTry () } } - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, messageCode: "IL2072")] public static void TestBranchCatch () { string str = GetWithPublicMethods (); @@ -317,7 +302,7 @@ public static void TestBranchCatch () } } - [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (LocalDataFlow), nameof (RequirePublicFields), new Type[] { typeof (string) }, messageCode: "IL2072")] public static void TestBranchFinally () { string str = GetWithPublicMethods (); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs index c6d287d42df7..ce2c49047be8 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs @@ -39,22 +39,18 @@ public static void Main () // Validate the error message when annotated parameter is passed to another annotated parameter [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, - "The parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.MethodParametersDataFlow.PublicParameterlessConstructorParameter(Type)' " + - "with dynamically accessed member kinds 'PublicParameterlessConstructor' is passed into the parameter 'type' " + - "of method 'Mono.Linker.Tests.Cases.DataFlow.MethodParametersDataFlow.RequirePublicConstructors(Type)' " + - "which requires dynamically accessed member kinds 'PublicConstructors'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicConstructors'.")] - [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + messageCode: "IL2067", message: new string[] { "sourceType", "PublicParameterlessConstructorParameter(Type)", "type", "RequirePublicConstructors(Type)" })] + [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2067")] private static void PublicParameterlessConstructorParameter ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] - Type type) + Type sourceType) { - RequirePublicParameterlessConstructor (type); - RequirePublicConstructors (type); - RequireNonPublicConstructors (type); + RequirePublicParameterlessConstructor (sourceType); + RequirePublicConstructors (sourceType); + RequireNonPublicConstructors (sourceType); } - [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2067")] private static void PublicConstructorsParameter ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) @@ -64,8 +60,8 @@ private static void PublicConstructorsParameter ( RequireNonPublicConstructors (type); } - [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (Type) }, messageCode: "IL2067")] + [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2067")] private static void NonPublicConstructorsParameter ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type) @@ -75,7 +71,7 @@ private static void NonPublicConstructorsParameter ( RequireNonPublicConstructors (type); } - [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2067")] private void InstanceMethod ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type) @@ -84,7 +80,7 @@ private void InstanceMethod ( RequirePublicConstructors (type); } - [UnrecognizedReflectionAccessPattern (typeof (Type), "type")] + [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")] private void WriteToParameterOnInstanceMethod ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type) @@ -92,7 +88,7 @@ private void WriteToParameterOnInstanceMethod ( type = ReturnThingsWithPublicParameterlessConstructor (); } - [UnrecognizedReflectionAccessPattern (typeof (Type), "type")] + [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")] private static void WriteToParameterOnStaticMethod ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type) @@ -100,7 +96,7 @@ private static void WriteToParameterOnStaticMethod ( type = ReturnThingsWithPublicParameterlessConstructor (); } - [UnrecognizedReflectionAccessPattern (typeof (Type), "type")] + [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")] private void LongWriteToParameterOnInstanceMethod ( int a, int b, int c, int d, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] @@ -109,7 +105,7 @@ private void LongWriteToParameterOnInstanceMethod ( type = ReturnThingsWithPublicParameterlessConstructor (); } - [UnrecognizedReflectionAccessPattern (typeof (Type), "type")] + [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")] private static void LongWriteToParameterOnStaticMethod ( int a, int b, int c, int d, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] @@ -124,7 +120,7 @@ static private Type ReturnThingsWithPublicParameterlessConstructor () return null; } - [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2067")] private void TwoAnnotatedParameters ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type, @@ -137,7 +133,7 @@ private void TwoAnnotatedParameters ( RequirePublicConstructors (type2); } - [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2067")] private void TwoAnnotatedParametersIntoOneValue ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type, @@ -151,11 +147,7 @@ private void TwoAnnotatedParametersIntoOneValue ( // Validate the error message for the case of unannotated method return value passed to an annotated parameter. [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (Type) }, - "The parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.MethodParametersDataFlow.NoAnnotation(Type)' " + - "with dynamically accessed member kinds 'None' is passed into " + - "the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.MethodParametersDataFlow.RequirePublicParameterlessConstructor(Type)' " + - "which requires dynamically accessed member kinds 'PublicParameterlessConstructor'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicParameterlessConstructor'.")] + messageCode: "IL2067", message: new string[] { "type", "NoAnnotation(Type)", "type", "RequirePublicParameterlessConstructor(Type)" })] private void NoAnnotation (Type type) { RequirePublicParameterlessConstructor (type); @@ -163,10 +155,7 @@ private void NoAnnotation (Type type) // Validate error message when untracable value is passed to an annotated parameter. [UnrecognizedReflectionAccessPattern (typeof (MethodParametersDataFlow), nameof (RequirePublicParameterlessConstructor), new Type[] { typeof (Type) }, - "A value from unknown source is passed " + - "into the parameter 'type' of method 'Mono.Linker.Tests.Cases.DataFlow.MethodParametersDataFlow.RequirePublicParameterlessConstructor(Type)' " + - "which requires dynamically accessed member kinds 'PublicParameterlessConstructor'. " + - "It's not possible to guarantee that these requirements are met by the application.")] + messageCode: "IL2062", message: new string[] { "type", "RequirePublicParameterlessConstructor" })] private void UnknownValue () { var array = new object[1]; diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs index 2c11fc8a5cc0..5cebf613e65e 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs @@ -28,10 +28,12 @@ public static void Main () instance.ReturnPublicParameterlessConstructorFromNull (); instance.ReturnPublicConstructorsFailure (null); instance.ReturnNonPublicConstructorsFailure (null); + instance.ReturnUnknownValue (); // Validation that value comming from return value of a method is correctly propagated instance.PropagateReturnPublicParameterlessConstructor (); instance.PropagateReturnPublicParameterlessConstructorFromConstant (); + instance.PropagateReturnToReturn (0); } private static Type NoRequirements () @@ -40,7 +42,7 @@ private static Type NoRequirements () } [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (ReturnPublicParameterlessConstructor), - new Type[] { typeof (Type), typeof (Type), typeof (Type) }, returnType: typeof (Type))] + new Type[] { typeof (Type), typeof (Type), typeof (Type) }, returnType: typeof (Type), messageCode: "IL2068")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] private Type ReturnPublicParameterlessConstructor ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] @@ -65,7 +67,7 @@ private Type ReturnPublicParameterlessConstructor ( } [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (ReturnPublicParameterlessConstructorFromUnknownType), - new Type[] { typeof (Type) }, returnType: typeof (Type))] + new Type[] { typeof (Type) }, returnType: typeof (Type), messageCode: "IL2068")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] private Type ReturnPublicParameterlessConstructorFromUnknownType (Type unknownType) { @@ -86,14 +88,18 @@ private Type ReturnPublicParameterlessConstructorFromNull () return null; } + private Type ReturnTypeWithNoRequirements () + { + return null; + } + // Validate error message when insufficiently annotated value is returned from a method [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (ReturnPublicConstructorsFailure), - new Type[] { typeof (Type) }, - "The parameter 'publicParameterlessConstructorType' of method 'Mono.Linker.Tests.Cases.DataFlow.MethodReturnParameterDataFlow.ReturnPublicConstructorsFailure(Type)' " + - "with dynamically accessed member kinds 'PublicParameterlessConstructor' is " + - "passed into the return value of method 'Mono.Linker.Tests.Cases.DataFlow.MethodReturnParameterDataFlow.ReturnPublicConstructorsFailure(Type)' " + - "which requires dynamically accessed member kinds 'PublicConstructors'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicConstructors'.", typeof (Type))] + new Type[] { typeof (Type) }, returnType: typeof (Type), + messageCode: "IL2068", message: new string[] { + "publicParameterlessConstructorType", + "MethodReturnParameterDataFlow.ReturnPublicConstructorsFailure", + "MethodReturnParameterDataFlow.ReturnPublicConstructorsFailure" })] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] private Type ReturnPublicConstructorsFailure ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] @@ -103,7 +109,7 @@ private Type ReturnPublicConstructorsFailure ( } [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (ReturnNonPublicConstructorsFailure), - new Type[] { typeof (Type) }, returnType: typeof (Type))] + new Type[] { typeof (Type) }, returnType: typeof (Type), messageCode: "IL2068")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] private Type ReturnNonPublicConstructorsFailure ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] @@ -112,8 +118,19 @@ private Type ReturnNonPublicConstructorsFailure ( return publicConstructorsType; } - [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (ReturnUnknownValue), + new Type[] { }, returnType: typeof (Type), + messageCode: "IL2063", message: nameof (ReturnUnknownValue))] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + private Type ReturnUnknownValue () + { + var array = new object[1]; + array[0] = this.GetType (); + return (Type) array[0]; + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] private void PropagateReturnPublicParameterlessConstructor () { Type t = ReturnPublicParameterlessConstructor (typeof (TestType), typeof (TestType), typeof (TestType)); @@ -123,8 +140,8 @@ private void PropagateReturnPublicParameterlessConstructor () RequireNothing (t); } - [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] private void PropagateReturnPublicParameterlessConstructorFromConstant () { Type t = ReturnPublicParameterlessConstructorFromConstant (); @@ -134,6 +151,24 @@ private void PropagateReturnPublicParameterlessConstructorFromConstant () RequireNothing (t); } + [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (PropagateReturnToReturn), new Type[] { typeof (int) }, returnType: typeof (Type), + messageCode: "IL2073", message: new string[] { + nameof (ReturnTypeWithNoRequirements), + nameof (PropagateReturnToReturn) + })] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + private Type PropagateReturnToReturn (int n) + { + switch (n) { + case 0: + return ReturnPublicParameterlessConstructorFromConstant (); + case 1: + return ReturnTypeWithNoRequirements (); + } + + return null; + } + private static void PublicParameterlessConstructorConstructor ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type) diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs index 4c9fc215d8fd..e04fb56e19f3 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs @@ -22,15 +22,18 @@ public static void Main () PropagateToThisWithSetters (); TestAnnotationOnNonTypeMethod (); + TestUnknownThis (); + TestFromParameterToThis (null); + TestFromFieldToThis (); + TestFromThisToOthers (); + TestFromGenericParameterToThis (); } [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods), new Type[] { }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.GetWithNonPublicMethods()' " + - "with dynamically accessed member kinds 'NonPublicMethods' " + - "is passed into the implicit 'this' parameter of method 'System.MethodThisDataFlowTypeTest.RequireThisPublicMethods()' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisNonPublicMethods), new Type[] { })] + messageCode: "IL2075", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.GetWithNonPublicMethods()", + "System.MethodThisDataFlowTypeTest.RequireThisPublicMethods()" })] + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisNonPublicMethods), new Type[] { }, messageCode: "IL2075")] static void PropagateToThis () { GetWithPublicMethods ().RequireThisPublicMethods (); @@ -41,12 +44,10 @@ static void PropagateToThis () } [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), "get_" + nameof (MethodThisDataFlowTypeTest.PropertyRequireThisPublicMethods), new Type[] { }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.GetWithNonPublicMethods()' " + - "with dynamically accessed member kinds 'NonPublicMethods' " + - "is passed into the implicit 'this' parameter of method 'System.MethodThisDataFlowTypeTest.get_PropertyRequireThisPublicMethods()' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), "get_" + nameof (MethodThisDataFlowTypeTest.PropertyRequireThisNonPublicMethods), new Type[] { })] + messageCode: "IL2075", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.GetWithNonPublicMethods()", + "System.MethodThisDataFlowTypeTest.get_PropertyRequireThisPublicMethods()" })] + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), "get_" + nameof (MethodThisDataFlowTypeTest.PropertyRequireThisNonPublicMethods), new Type[] { }, messageCode: "IL2075")] static void PropagateToThisWithGetters () { _ = GetWithPublicMethods ().PropertyRequireThisPublicMethods; @@ -57,12 +58,10 @@ static void PropagateToThisWithGetters () } [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), "set_" + nameof (MethodThisDataFlowTypeTest.PropertyRequireThisPublicMethods), new Type[] { typeof (Object) }, - "The return value of method 'Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.GetWithNonPublicMethods()' " + - "with dynamically accessed member kinds 'NonPublicMethods' " + - "is passed into the implicit 'this' parameter of method 'System.MethodThisDataFlowTypeTest.set_PropertyRequireThisPublicMethods(Object)' " + - "which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), "set_" + nameof (MethodThisDataFlowTypeTest.PropertyRequireThisNonPublicMethods), new Type[] { typeof (Object) })] + messageCode: "IL2075", message: new string[] { + "Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.GetWithNonPublicMethods()", + "System.MethodThisDataFlowTypeTest.set_PropertyRequireThisPublicMethods(Object)" })] + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), "set_" + nameof (MethodThisDataFlowTypeTest.PropertyRequireThisNonPublicMethods), new Type[] { typeof (Object) }, messageCode: "IL2075")] static void PropagateToThisWithSetters () { GetWithPublicMethods ().PropertyRequireThisPublicMethods = null; @@ -88,20 +87,62 @@ static void TestAnnotationOnNonTypeMethod () { var t = new NonTypeType (); t.GetMethod ("foo"); + NonTypeType.StaticMethod (); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisNonPublicMethods), new Type[] { }, + messageCode: "IL2065", message: nameof (MethodThisDataFlowTypeTest.RequireThisNonPublicMethods))] + static void TestUnknownThis () + { + var array = new object[1]; + array[0] = array.GetType (); + ((MethodThisDataFlowTypeTest) array[0]).RequireThisNonPublicMethods (); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods), new Type[] { }, + messageCode: "IL2070", message: new string[] { "sourceType", nameof (TestFromParameterToThis), nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods) })] + static void TestFromParameterToThis (MethodThisDataFlowTypeTest sourceType) + { + sourceType.RequireThisPublicMethods (); + } + + static MethodThisDataFlowTypeTest _typeField; + + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods), new Type[] { }, + messageCode: "IL2080", message: new string[] { nameof (_typeField), nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods) })] + static void TestFromFieldToThis () + { + _typeField.RequireThisPublicMethods (); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods), new Type[] { }, + messageCode: "IL2090", message: new string[] { + "TSource", + "TestFromGenericParameterToThis", + nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods) + })] + static void TestFromGenericParameterToThis () + { + ((MethodThisDataFlowTypeTest) typeof (TSource)).RequireThisPublicMethods (); + } + + static void TestFromThisToOthers () + { + GetWithPublicMethods ().PropagateToReturn (); + GetWithPublicMethods ().PropagateToField (); + GetWithPublicMethods ().PropagateToThis (); } class NonTypeType { - [LogContains ("warning IL2041: Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.NonTypeType.GetMethod(String): " + - "The DynamicallyAccessedMembersAttribute is only allowed on method parameters, return value or generic parameters.")] + [ExpectedWarning ("IL2041")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] public MethodInfo GetMethod (string name) { return null; } - [LogContains ("warning IL2041: Mono.Linker.Tests.Cases.DataFlow.MethodThisDataFlow.NonTypeType.StaticMethod(): " + - "The DynamicallyAccessedMembersAttribute is only allowed on method parameters, return value or generic parameters.")] + [ExpectedWarning ("IL2041")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] public static void StaticMethod () { @@ -116,11 +157,9 @@ class MethodThisDataFlowTypeTest : TestSystemTypeBase { [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (RequireNonPublicMethods), new Type[] { typeof (Type) }, - "The implicit 'this' parameter of method 'System.MethodThisDataFlowTypeTest.RequireThisPublicMethods()' " + - "with dynamically accessed member kinds 'PublicMethods' " + - "is passed into the parameter 'type' of method 'System.MethodThisDataFlowTypeTest.RequireNonPublicMethods(Type)' " + - "which requires dynamically accessed member kinds 'NonPublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'NonPublicMethods'.")] + messageCode: "IL2082", message: new string[] { + "implicit 'this' parameter of method 'System.MethodThisDataFlowTypeTest.RequireThisPublicMethods()'", + "parameter 'type' of method 'System.MethodThisDataFlowTypeTest.RequireNonPublicMethods(Type)'" })] public void RequireThisPublicMethods () { RequirePublicMethods (this); @@ -128,13 +167,51 @@ public void RequireThisPublicMethods () } [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] - [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (RequirePublicMethods), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (RequirePublicMethods), new Type[] { typeof (Type) }, + messageCode: "IL2082")] public void RequireThisNonPublicMethods () { RequirePublicMethods (this); RequireNonPublicMethods (this); } + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (PropagateToReturn), new Type[] { }, returnType: typeof (Type), + messageCode: "IL2083", message: new string[] { + nameof(PropagateToReturn), + nameof(PropagateToReturn) + })] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + public Type PropagateToReturn () + { + return this; + } + + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + Type _requiresPublicConstructors; + + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (_requiresPublicConstructors), + messageCode: "IL2084", message: new string[] { + nameof (PropagateToField), + nameof (_requiresPublicConstructors) + })] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public void PropagateToField () + { + _requiresPublicConstructors = this; + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (RequireThisNonPublicMethods), new Type[] { }, + messageCode: "IL2085", message: new string[] { + nameof (PropagateToThis), + nameof (RequireThisNonPublicMethods) + })] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public void PropagateToThis () + { + this.RequireThisNonPublicMethods (); + } + public object PropertyRequireThisPublicMethods { [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] get { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs index 4cef0c7a4921..2d7e7363b551 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs @@ -43,7 +43,7 @@ public static void Main () [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] static Type StaticPropertyWithPublicConstructor { get; set; } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] private void ReadFromInstanceProperty () { RequirePublicParameterlessConstructor (PropertyWithPublicConstructor); @@ -52,7 +52,7 @@ private void ReadFromInstanceProperty () RequireNothing (PropertyWithPublicConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] private void ReadFromStaticProperty () { RequirePublicParameterlessConstructor (StaticPropertyWithPublicConstructor); @@ -61,9 +61,9 @@ private void ReadFromStaticProperty () RequireNothing (StaticPropertyWithPublicConstructor); } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (PropertyWithPublicConstructor), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (PropertyWithPublicConstructor), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (PropertyWithPublicConstructor), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (PropertyWithPublicConstructor), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (PropertyWithPublicConstructor), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (PropertyWithPublicConstructor), new Type[] { typeof (Type) }, messageCode: "IL2072")] private void WriteToInstanceProperty () { PropertyWithPublicConstructor = GetTypeWithPublicParameterlessConstructor (); @@ -72,9 +72,9 @@ private void WriteToInstanceProperty () PropertyWithPublicConstructor = GetUnkownType (); } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (StaticPropertyWithPublicConstructor), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (StaticPropertyWithPublicConstructor), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (StaticPropertyWithPublicConstructor), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (StaticPropertyWithPublicConstructor), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (StaticPropertyWithPublicConstructor), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "set_" + nameof (StaticPropertyWithPublicConstructor), new Type[] { typeof (Type) }, messageCode: "IL2072")] private void WriteToStaticProperty () { StaticPropertyWithPublicConstructor = GetTypeWithPublicParameterlessConstructor (); @@ -107,7 +107,8 @@ Type PropertyPublicParameterlessConstructorWithExplicitAccessors { return _fieldWithPublicConstructors; } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (_fieldWithPublicConstructors))] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (_fieldWithPublicConstructors), + messageCode: "IL2069", message: new string[] { "value", "set_" + nameof (PropertyPublicParameterlessConstructorWithExplicitAccessors), nameof (_fieldWithPublicConstructors) })] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] set { _fieldWithPublicConstructors = value; @@ -116,13 +117,16 @@ Type PropertyPublicParameterlessConstructorWithExplicitAccessors { Type PropertyNonPublicConstructorsWithExplicitAccessors { [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), "get_" + nameof (PropertyNonPublicConstructorsWithExplicitAccessors), - new Type[] { }, returnType: typeof (Type))] + new Type[] { }, returnType: typeof (Type), messageCode: "IL2078", message: new string[] { + nameof (_fieldWithPublicConstructors), + "get_" + nameof (PropertyNonPublicConstructorsWithExplicitAccessors) + })] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] get { return _fieldWithPublicConstructors; } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (_fieldWithPublicConstructors))] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (_fieldWithPublicConstructors), messageCode: "IL2069")] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)] set { _fieldWithPublicConstructors = value; @@ -143,7 +147,7 @@ static void TestAutomaticPropagation () class TestAutomaticPropagationType { // Fully implicit property should work - [UnrecognizedReflectionAccessPattern (typeof (TestAutomaticPropagationType), "set_" + nameof (ImplicitProperty), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (TestAutomaticPropagationType), "set_" + nameof (ImplicitProperty), new Type[] { typeof (Type) }, messageCode: "IL2072")] public void TestImplicitProperty () { RequirePublicConstructors (ImplicitProperty); @@ -156,7 +160,7 @@ static Type ImplicitProperty { } // Simple getter is not enough - we do detect the field, but we require the field to be compiler generated for this to work - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] // Make sure we don't warn about the field in context of property annotation propagation. [LogDoesNotContain ("Could not find a unique backing field for property 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithSimpleGetter()'")] public void TestPropertyWithSimpleGetter () @@ -169,7 +173,7 @@ public void TestPropertyWithSimpleGetter () [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] static Type PropertyWithSimpleGetter { - [UnrecognizedReflectionAccessPattern (typeof (TestAutomaticPropagationType), "get_" + nameof (PropertyWithSimpleGetter), new Type[] { }, returnType: typeof (Type))] + [UnrecognizedReflectionAccessPattern (typeof (TestAutomaticPropagationType), "get_" + nameof (PropertyWithSimpleGetter), new Type[] { }, returnType: typeof (Type), messageCode: "IL2078")] get { return PropertyWithSimpleGetter_Field; } @@ -193,7 +197,7 @@ static Type PropertyWhichLooksLikeCompilerGenerated { } } - [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (PropertyDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] // Make sure we don't warn about the field in context of property annotation propagation. [LogDoesNotContain ("Could not find a unique backing field for property 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::InstancePropertyWithStaticField()'")] public void TestInstancePropertyWithStaticField () @@ -215,10 +219,6 @@ Type InstancePropertyWithStaticField { } } - [LogContains ("Could not find a unique backing field for property 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithDifferentBackingFields()' " + - "to propagate DynamicallyAccessedMembersAttribute. " + - "The backing fields from getter 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithDifferentBackingFields_GetterField' " + - "and setter 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithDifferentBackingFields_SetterField' are not the same.")] public void TestPropertyWithDifferentBackingFields () { _ = PropertyWithDifferentBackingFields; @@ -230,6 +230,8 @@ public void TestPropertyWithDifferentBackingFields () [CompilerGenerated] private Type PropertyWithDifferentBackingFields_SetterField; + [ExpectedWarning ("IL2042", + "System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithDifferentBackingFields()")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type PropertyWithDifferentBackingFields { get { @@ -241,23 +243,24 @@ Type PropertyWithDifferentBackingFields { } } - [LogContains ("Trying to propagate DynamicallyAccessedMemberAttribute from property 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithExistingAttributes()' to its field 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithExistingAttributes_Field', but it already has such attribute.")] - [LogContains ("Trying to propagate DynamicallyAccessedMemberAttribute from property 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithExistingAttributes()' to its setter 'Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.set_PropertyWithExistingAttributes(Type)', but it already has such attribute on the 'value' parameter.")] - [LogContains ("Trying to propagate DynamicallyAccessedMemberAttribute from property 'System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithExistingAttributes()' to its getter 'Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.get_PropertyWithExistingAttributes()', but it already has such attribute on the return value.")] public void TestPropertyWithExistingAttributes () { _ = PropertyWithExistingAttributes; PropertyWithExistingAttributes = null; } + [ExpectedWarning ("IL2056", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes_Field")] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] [CompilerGenerated] Type PropertyWithExistingAttributes_Field; [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type PropertyWithExistingAttributes { + [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "get_PropertyWithExistingAttributes")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] get { return PropertyWithExistingAttributes_Field; } + + [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "set_PropertyWithExistingAttributes")] [param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] set { PropertyWithExistingAttributes_Field = value; } } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.cs b/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.cs index ed99137cad2a..903eeca10276 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.cs @@ -13,7 +13,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [SkipKeptItemsValidation] [SetupLinkAttributesFile ("SuppressWarningWithLinkAttributes.xml")] - [LogDoesNotContain ("Trim analysis warning IL2006: Mono.Linker.Tests.Cases.DataFlow.SuppressWarningWithLinkAttributes::ReadFromInstanceField()")] + [LogDoesNotContain ("Trim analysis warning IL2067: Mono.Linker.Tests.Cases.DataFlow.SuppressWarningWithLinkAttributes::ReadFromInstanceField()")] class SuppressWarningWithLinkAttributes { public static void Main () @@ -27,8 +27,8 @@ public static void Main () Type PropertyWithPublicParameterlessConstructor { get; set; } - [UnrecognizedReflectionAccessPattern (typeof (SuppressWarningWithLinkAttributes), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (SuppressWarningWithLinkAttributes), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (SuppressWarningWithLinkAttributes), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] + [UnrecognizedReflectionAccessPattern (typeof (SuppressWarningWithLinkAttributes), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2077")] [RecognizedReflectionAccessPattern] private void ReadFromInstanceField () { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml b/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml index 335a2e521585..57889aafda0b 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml @@ -3,7 +3,7 @@ Test - IL2006 + IL2067 diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs b/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs index bf1418882277..d28d2c81515e 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/VirtualMethodHierarchyDataflowAnnotationValidation.cs @@ -137,10 +137,7 @@ class DerivedClass : BaseClass [LogDoesNotContain ("DerivedClass.ReturnValueBaseWithoutDerivedWithout")] public override Type ReturnValueBaseWithoutDerivedWithout () => null; - [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.ReturnValueBaseWithoutDerivedWith()' " + - "don't match overridden return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.ReturnValueBaseWithoutDerivedWith()'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + [ExpectedWarning ("IL2093", "BaseClass.ReturnValueBaseWithoutDerivedWith", "DerivedClass.ReturnValueBaseWithoutDerivedWith")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] public override Type ReturnValueBaseWithoutDerivedWith () => null; @@ -153,10 +150,9 @@ class DerivedClass : BaseClass // === Method parameters === - [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.SingleParameterBaseWithDerivedWithout(Type)' " + - "don't match overridden parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.SingleParameterBaseWithDerivedWithout(Type)'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + [ExpectedWarning ("IL2092", + "p", "Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.SingleParameterBaseWithDerivedWithout(Type)", + "p", "Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.SingleParameterBaseWithDerivedWithout(Type)")] public override void SingleParameterBaseWithDerivedWithout (Type p) { } [LogDoesNotContain ("DerivedClass.SingleParameterBaseWithDerivedWith_")] @@ -166,9 +162,9 @@ public override void SingleParameterBaseWithDerivedWith_ ( { } [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.SingleParameterBaseWithoutDerivedWith_(Type)' " + + "'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.SingleParameterBaseWithoutDerivedWith_(Type)' " + "don't match overridden parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.SingleParameterBaseWithoutDerivedWith_(Type)'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + "All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.")] public override void SingleParameterBaseWithoutDerivedWith_ ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type p) @@ -178,9 +174,9 @@ public override void SingleParameterBaseWithoutDerivedWith_ ( public override void SingleParameterBaseWithoutDerivedWithout (Type p) { } [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.SingleParameterBaseWithDerivedWithDifferent(Type)' " + + "'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.SingleParameterBaseWithDerivedWithDifferent(Type)' " + "don't match overridden parameter 'p' of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.SingleParameterBaseWithDerivedWithDifferent(Type)'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + "All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.")] public override void SingleParameterBaseWithDerivedWithDifferent ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type p) @@ -231,16 +227,15 @@ public override void MultipleParametersBaseWithDerivedWithMismatch ( { } // === Generic methods === - [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.GenericBaseWithDerivedWithout()' " + - "don't match overridden generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.GenericBaseWithDerivedWithout()'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + [ExpectedWarning ("IL2095", + "T", "Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.GenericBaseWithDerivedWithout()", + "T", "Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.GenericBaseWithDerivedWithout()")] public override void GenericBaseWithDerivedWithout () { } [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.GenericBaseWithoutDerivedWith()' " + - "don't match overridden generic parameter 'T' from 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.GenericBaseWithoutDerivedWith()'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + "'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the generic parameter 'T' of 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.GenericBaseWithoutDerivedWith()' " + + "don't match overridden generic parameter 'T' of 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.GenericBaseWithoutDerivedWith()'. " + + "All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.")] public override void GenericBaseWithoutDerivedWith<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]T> () { } [LogDoesNotContain ("DerivedClass.GenericBaseWithDerivedWith_")] @@ -254,9 +249,9 @@ public override void GenericBaseWithoutDerivedWithout () { } // The warning is reported on the getter (or setter), which is not ideal, but it's probably good enough for now (we don't internally track annotations // on properties themselves, only on methods). [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.get_PropertyBaseWithDerivedWithout()' " + + "'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.get_PropertyBaseWithDerivedWithout()' " + "don't match overridden return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.get_PropertyBaseWithDerivedWithout()'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + "All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.")] public override Type PropertyBaseWithDerivedWithout { get; } [LogDoesNotContain ("DerivedClass.get_PropertyBaseWithDerivedWith_")] @@ -271,14 +266,14 @@ public override void GenericBaseWithoutDerivedWithout () { } // === RequiresUnreferencedCode === [LogContains ( - "Presence of RequiresUnreferencedCodeAttribute on method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.RequiresUnreferencedCodeBaseWithDerivedWithout()' " + + "Presence of 'RequiresUnreferencedCodeAttribute' on method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.RequiresUnreferencedCodeBaseWithDerivedWithout()' " + "doesn't match overridden method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.RequiresUnreferencedCodeBaseWithDerivedWithout()'. " + - "All overridden methods must have RequiresUnreferencedCodeAttribute.")] + "All overridden methods must have 'RequiresUnreferencedCodeAttribute'.")] public override void RequiresUnreferencedCodeBaseWithDerivedWithout () { } [LogContains ( - "Presence of RequiresUnreferencedCodeAttribute on method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.RequiresUnreferencedCodeBaseWithoutDerivedWith_()' " + + "Presence of 'RequiresUnreferencedCodeAttribute' on method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.DerivedClass.RequiresUnreferencedCodeBaseWithoutDerivedWith_()' " + "doesn't match overridden method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.RequiresUnreferencedCodeBaseWithoutDerivedWith_()'. " + - "All overridden methods must have RequiresUnreferencedCodeAttribute.")] + "All overridden methods must have 'RequiresUnreferencedCodeAttribute'.")] [RequiresUnreferencedCode ("")] public override void RequiresUnreferencedCodeBaseWithoutDerivedWith_ () { } [LogDoesNotContain ("DerivedClass.RequiresUnreferencedCodeBaseWithDerivedWith_")] @@ -297,9 +292,9 @@ class SuperDerivedClass : InBetweenDerived { // === Return values === [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.SuperDerivedClass.ReturnValueBaseWithSuperDerivedWithout()' " + + "'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.SuperDerivedClass.ReturnValueBaseWithSuperDerivedWithout()' " + "don't match overridden return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseClass.ReturnValueBaseWithSuperDerivedWithout()'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + "All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.")] public override Type ReturnValueBaseWithSuperDerivedWithout () => null; // === RequiresUnreferencedCode === @@ -566,9 +561,9 @@ interface IBaseImplementedInterface class BaseImplementsInterfaceViaDerived { [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseImplementsInterfaceViaDerived.ReturnValueBaseWithInterfaceWithout()' " + + "'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.BaseImplementsInterfaceViaDerived.ReturnValueBaseWithInterfaceWithout()' " + "don't match overridden return value of method 'Mono.Linker.Tests.Cases.DataFlow.VirtualMethodHierarchyDataflowAnnotationValidation.IBaseImplementedInterface.ReturnValueBaseWithInterfaceWithout()'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + "All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] public virtual Type ReturnValueBaseWithInterfaceWithout () => null; @@ -615,10 +610,9 @@ public virtual void ThisBaseWithoutDerivedWith () { } class VirtualMethodHierarchyDataflowAnnotationValidationTypeTestDerived : VirtualMethodHierarchyDataflowAnnotationValidationTypeTestBase { - [LogContains ( - "DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on implicit 'this' parameter of method 'System.VirtualMethodHierarchyDataflowAnnotationValidationTypeTestDerived.ThisBaseWithDerivedWithout()' " + - "don't match overridden implicit 'this' parameter of method 'System.VirtualMethodHierarchyDataflowAnnotationValidationTypeTestBase.ThisBaseWithDerivedWithout()'. " + - "All overridden members must have the same DynamicallyAccessedMembersAttribute usage.")] + [ExpectedWarning ("IL2094", + "System.VirtualMethodHierarchyDataflowAnnotationValidationTypeTestDerived.ThisBaseWithDerivedWithout()", + "System.VirtualMethodHierarchyDataflowAnnotationValidationTypeTestBase.ThisBaseWithDerivedWithout()")] public override void ThisBaseWithDerivedWithout () { } [LogDoesNotContain ("VirtualMethodHierarchyDataflowAnnotationValidationTypeTestDerived.ThisBaseWithDerivedWith_")] diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs index ac6e536f740b..1e6fbd348368 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs @@ -13,8 +13,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [SkipKeptItemsValidation] [SetupLinkAttributesFile ("XmlAnnotations.xml")] - [LogContains ("XmlAnnotations.xml: warning IL2031: Attribute type 'System.DoesNotExistAttribute' could not be found")] - [LogDoesNotContain ("IL2006: Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField():*", true)] + [ExpectedWarning ("IL2031", "System.DoesNotExistAttribute", FileName = "XmlAnnotations.xml")] + [LogDoesNotContain ("IL2067: Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField():*", true)] class XmlAnnotations { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml index 2747c62634e8..46fb37653de5 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml @@ -3,7 +3,7 @@ ILLink - IL2006 + IL2067 member M:Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs index e4bc47f9b6a5..16860231da73 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs @@ -5,10 +5,6 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies { - [LogContains ("IL2037: Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.B.Broken(): No members were resolved for 'MissingMethod'.")] - [LogContains ("IL2037: Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.B.Broken(): No members were resolved for 'Dependency2``1(``0,System.Int32,System.Object)'.")] - [LogContains ("IL2037: Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.B.Broken(): No members were resolved for '#ctor()'.")] - [LogContains ("IL2037: Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.B.Broken(): No members were resolved for '#cctor()'.")] class DynamicDependencyMethod { public static void Main () @@ -61,11 +57,24 @@ public static void SameContext () } [Kept] + + [ExpectedWarning ("IL2037", "MissingMethod")] [DynamicDependency ("MissingMethod", typeof (C))] + + [ExpectedWarning ("IL2037", "Dependency2``1(``0,System.Int32,System.Object)")] [DynamicDependency ("Dependency2``1(``0,System.Int32,System.Object)", typeof (C))] + + [ExpectedWarning ("IL2037", "''")] [DynamicDependency ("")] + + [ExpectedWarning ("IL2037", "#ctor()")] [DynamicDependency ("#ctor()", typeof (NestedStruct))] + + [ExpectedWarning ("IL2037", "#cctor()")] [DynamicDependency ("#cctor()", typeof (C))] + + [ExpectedWarning ("IL2036", "NonExistentType")] + [DynamicDependency ("method", "NonExistentType", "test")] public static void Broken () { } diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs index be03791c4132..28c51d852545 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs @@ -8,6 +8,7 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", ".ctor()")] [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "privateField")] [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs" })] + [SetupLinkerArgument ("--skip-unresolved", "true")] public class DynamicDependencyMethodInAssembly { public static void Main () @@ -18,6 +19,9 @@ public static void Main () [Kept] [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")] [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicFields, "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")] + + [ExpectedWarning ("IL2035", "NonExistentAssembly")] + [DynamicDependency ("method", "type", "NonExistentAssembly")] static void Dependency () { } diff --git a/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsInvalid.cs b/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsInvalid.cs index fec9230aa742..bea05a67d2ad 100644 --- a/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsInvalid.cs +++ b/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsInvalid.cs @@ -8,8 +8,8 @@ namespace Mono.Linker.Tests.Cases.FeatureSettings [LogContains ("FeatureSubstitutionsInvalid.xml'. Feature 'NoValueFeature' does not specify a 'featurevalue' attribute")] [LogContains ("FeatureSubstitutionsInvalid.xml'. Unsupported non-boolean feature definition 'NonBooleanFeature'")] [LogContains ("FeatureSubstitutionsInvalid.xml'. Unsupported value for featuredefault attribute")] - [LogContains ("warning IL2012: Could not find field 'NonExistentField' in type 'Mono.Linker.Tests.Cases.FeatureSettings.FeatureSubstitutionsInvalid.Foo'")] - [LogContains ("warning IL2009: Could not find method 'NonExistentMethod' in type 'Mono.Linker.Tests.Cases.FeatureSettings.FeatureSubstitutionsInvalid.Foo'")] + [LogContains ("warning IL2012: Could not find field 'NonExistentField' on type 'Mono.Linker.Tests.Cases.FeatureSettings.FeatureSubstitutionsInvalid.Foo'")] + [LogContains ("warning IL2009: Could not find method 'NonExistentMethod' on type 'Mono.Linker.Tests.Cases.FeatureSettings.FeatureSubstitutionsInvalid.Foo'")] public class FeatureSubstitutionsInvalid { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs new file mode 100644 index 000000000000..3d9e90262064 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.LinkAttributes +{ + [SetupLinkAttributesFile ("LinkAttributeErrorCases.xml")] + [IgnoreLinkAttributes (false)] + [SetupLinkerArgument ("--skip-unresolved", "true")] + + [ExpectedWarning ("IL2007", "NonExistentAssembly2", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2030", "NonExistentAssembly1", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2030", "MalformedAssemblyName, thisiswrong", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2031", "NonExistentAttribute", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2054", "NonExistentEnumValue", "AttributeWithEnumParameterAttribute", "AttributeEnum", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2054", "NotANumber", "AttributeWithIntParameterAttribute", "System.Int32", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2022", "AttributeWithNoParametersAttribute", "1", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2023", "GetTypeMethod", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2024", "methodParameter", "MethodWithParameter", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2029", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2029", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2051", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2052", "NonExistentPropertyName", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2053", "StringValue", "IntProperty", FileName = "LinkAttributeErrorCases.xml")] + class LinkAttributeErrorCases + { + public static void Main () + { + + } + + public enum AttributeEnum + { + None + } + + public class AttributeWithEnumParameterAttribute : Attribute + { + public AttributeWithEnumParameterAttribute (AttributeEnum enumValue) + { + } + } + + public class AttributeWithIntParameterAttribute : Attribute + { + public AttributeWithIntParameterAttribute (int intValue) + { + } + } + + public class AttributeWithNoParametersAttribute : Attribute + { + public AttributeWithNoParametersAttribute () + { + } + } + + public class AttributeWithPropertyAttribute : Attribute + { + public AttributeWithPropertyAttribute () + { + } + + int IntProperty { get; } + } + + public class FirstAttribute : Attribute { } + public class SecondAttribute : Attribute { } + + public Type GetTypeMethod () => null; + + public void MethodWithParameter (int methodParameter) { } + } +} diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.xml new file mode 100644 index 000000000000..8d6608eba11b --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + ExtraArgumentValue + + + + + NonExistentEnumValue + + + + + NotANumber + + + + + StringValue + + + + + StringValue + + + + + StringValue + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs index 1454637b9e51..18bc4aa7d671 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.cs @@ -39,18 +39,13 @@ namespace Mono.Linker.Tests.Cases.LinkAttributes [KeptAssembly ("copyattribute.dll")] [KeptTypeInAssembly ("copyattribute.dll", typeof (AttributeFromCopyAssemblyAttribute))] - [LogContains ("IL2045: Mono.Linker.Tests.Cases.LinkAttributes.LinkerAttributeRemoval.TestType(): Custom Attribute System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute is " + - "being referenced in code but the linker was instructed to remove all instances of this attribute. If the attribute instances are necessary make sure to either remove " + - "the linker attribute XML portion which removes the attribute instances, or to override this use the linker XML descriptor to keep the attribute type (which in turn keeps all of its instances).")] - - [LogContains ("IL2045: Mono.Linker.Tests.Cases.LinkAttributes.Dependencies.TypeOnCopyAssemblyWithAttributeUsage.TypeOnCopyAssemblyWithAttributeUsage(): Custom Attribute Mono.Linker.Tests.Cases.LinkAttributes.Dependencies.TestAttributeReferencedAsTypeFromCopyAssemblyAttribute is " + - "being referenced in code but the linker was instructed to remove all instances of this attribute. If the attribute instances are necessary make sure to either remove " + - "the linker attribute XML portion which removes the attribute instances, or to override this use the linker XML descriptor to keep the attribute type (which in turn keeps all of its instances).")] + [LogContains ("IL2045: Mono.Linker.Tests.Cases.LinkAttributes.LinkerAttributeRemoval.TestType(): Attribute 'System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute'")] + [LogContains ("IL2045: Mono.Linker.Tests.Cases.LinkAttributes.Dependencies.TypeOnCopyAssemblyWithAttributeUsage.TypeOnCopyAssemblyWithAttributeUsage(): Attribute 'Mono.Linker.Tests.Cases.LinkAttributes.Dependencies.TestAttributeReferencedAsTypeFromCopyAssemblyAttribute'")] [LogDoesNotContain ("IL2045")] // No other 2045 messages should be logged - [LogContains ("IL2048: Internal attribute 'RemoveAttributeInstances' can only be used on a type, but is being used on 'System.String Mono.Linker.Tests.Cases.LinkAttributes.LinkerAttributeRemoval::methodWithCustomAttribute(System.String)'")] - [LogContains ("IL2049: Unrecognized internal attribute 'InvalidInternal'")] + [ExpectedWarning ("IL2048", "RemoveAttributeInstances", "methodWithCustomAttribute", FileName = "LinkerAttributeRemoval.xml")] + [ExpectedWarning ("IL2049", "InvalidInternal", FileName = "LinkerAttributeRemoval.xml")] [KeptMember (".ctor()")] class LinkerAttributeRemoval diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.xml index c31895628def..765933e25379 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.xml +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemoval.xml @@ -10,10 +10,12 @@ + + diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlUnresolvedReferencesAreReported.cs b/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlUnresolvedReferencesAreReported.cs index 46a8f85ef4b2..34065ac303aa 100644 --- a/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlUnresolvedReferencesAreReported.cs +++ b/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlUnresolvedReferencesAreReported.cs @@ -8,15 +8,15 @@ namespace Mono.Linker.Tests.Cases.LinkXml { [SetupLinkerDescriptorFile ("EmbeddedLinkXmlUnresolvedReferencesAreReported.xml")] [LogContains ("warning IL2008: Could not resolve type 'UnknownType'")] - [LogContains ("warning IL2012: Could not find field 'System.String FieldWithSignature' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2012: Could not find field 'UnknownField' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2009: Could not find method 'System.Void MethodWithSignature()' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2009: Could not find method 'UnknownMethod' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2016: Could not find event 'System.ResolveEventHandler EventWithSignature' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2016: Could not find event 'UnknownEvent' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2017: Could not find property 'System.String PropertyWithSignature' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2017: Could not find property 'UnknownProperty' in type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] - [LogContains ("warning IL2044: Could not find any type in namespace 'UnknownNamespace'")] + [LogContains ("warning IL2012: Could not find field 'System.String FieldWithSignature' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [LogContains ("warning IL2012: Could not find field 'UnknownField' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [LogContains ("warning IL2009: Could not find method 'System.Void MethodWithSignature()' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [LogContains ("warning IL2009: Could not find method 'UnknownMethod' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [LogContains ("warning IL2016: Could not find event 'System.ResolveEventHandler EventWithSignature' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [LogContains ("warning IL2016: Could not find event 'UnknownEvent' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [LogContains ("warning IL2017: Could not find property 'System.String PropertyWithSignature' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [LogContains ("warning IL2017: Could not find property 'UnknownProperty' on type 'Mono.Linker.Tests.Cases.LinkXml.EmbeddedLinkXmlUnresolvedReferencesAreReported.TestType'")] + [ExpectedWarning ("IL2044", "UnknownNamespace", FileName = "EmbeddedLinkXmlUnresolvedReferencesAreReported.xml")] class EmbeddedLinkXmlUnresolvedReferencesAreReported { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs new file mode 100644 index 000000000000..6b5303a5dfea --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs @@ -0,0 +1,76 @@ +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.LinkXml +{ + [SetupLinkerDescriptorFile ("LinkXmlErrorCases.xml")] + [SetupLinkerArgument ("--skip-unresolved", "true")] + + [ExpectedWarning ("IL2007", "NonExistentAssembly", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2008", "NonExistentType", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2009", "NonExistentMethod", "TypeWithNoMethods", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2012", "NonExistentField", "TypeWithNoFields", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2016", "NonExistentEvent", "TypeWithNoEvents", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2017", "NonExistentProperty", "TypeWithNoProperties", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2018", "SetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2019", "GetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml")] + + [ExpectedWarning ("IL2025", "Method", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2025", "Event", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2025", "Field", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2025", "Property", FileName = "LinkXmlErrorCases.xml")] + class LinkXmlErrorCases + { + public static void Main () + { + } + + [Kept] + [ExpectedWarning ("IL2001", "TypeWithNoFields")] + class TypeWithNoFields + { + private void Method () { } + } + + [Kept] + [ExpectedWarning ("IL2002", "TypeWithNoMethods")] + struct TypeWithNoMethods + { + } + + [Kept] + struct TypeWithNoEvents + { + } + + [Kept] + struct TypeWithNoProperties + { + } + + [Kept] + class TypeWithProperties + { + public bool SetOnlyProperty { set { _ = value; } } + public bool GetOnlyProperty { get { return false; } } + } + + [Kept] + class TypeWithEverything + { + [Kept] + public void Method () { } + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + public event EventHandler Event; + [Kept] + public int Field; + [Kept] + [KeptBackingField] + public int Property { [Kept] get; [Kept] set; } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml new file mode 100644 index 000000000000..dca7c7d2d735 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs b/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs index 2731a0d147ea..5d54b8515c95 100644 --- a/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs +++ b/test/Mono.Linker.Tests.Cases/Logging/SourceLines.cs @@ -9,14 +9,14 @@ namespace Mono.Linker.Tests.Cases.Logging [SkipKeptItemsValidation] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "../PreserveDependencies/Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileArgument ("/debug:full")] - [LogContains ("(37,4): Trim analysis warning IL2006: Mono.Linker.Tests.Cases.Logging.SourceLines.UnrecognizedReflectionPattern(): " + - "The return value of method 'Mono.Linker.Tests.Cases.Logging.SourceLines.GetUnknownType()' " + - "with dynamically accessed member kinds 'None' is passed into the field 'System.Type Mono.Linker.Tests.Cases.Logging.SourceLines::type' which requires dynamically " + - "accessed member kinds 'PublicConstructors'. To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicConstructors'.")] - [LogContains ("(38,4): Trim analysis warning IL2006: Mono.Linker.Tests.Cases.Logging.SourceLines.UnrecognizedReflectionPattern(): " + - "The return value of method 'Mono.Linker.Tests.Cases.Logging.SourceLines.GetUnknownType()' " + - "with dynamically accessed member kinds 'None' is passed into the field 'System.Type Mono.Linker.Tests.Cases.Logging.SourceLines::type' which requires dynamically " + - "accessed member kinds 'PublicConstructors'. To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicConstructors'.")] + [LogContains ("(37,4): Trim analysis warning IL2074: Mono.Linker.Tests.Cases.Logging.SourceLines.UnrecognizedReflectionPattern(): " + + "The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'Mono.Linker.Tests.Cases.Logging.SourceLines.GetUnknownType()' " + + "don't match those on the field 'System.Type Mono.Linker.Tests.Cases.Logging.SourceLines::type'. " + + "The source value must declare at least the same requirements as those declared on the target location it's assigned to ")] + [LogContains ("(38,4): Trim analysis warning IL2074: Mono.Linker.Tests.Cases.Logging.SourceLines.UnrecognizedReflectionPattern(): " + + "The requirements declared via the 'DynamicallyAccessedMembersAttribute' on the return value of method 'Mono.Linker.Tests.Cases.Logging.SourceLines.GetUnknownType()' " + + "don't match those on the field 'System.Type Mono.Linker.Tests.Cases.Logging.SourceLines::type'. " + + "The source value must declare at least the same requirements as those declared on the target location it's assigned to ")] public class SourceLines { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyDeprecated.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyDeprecated.cs index 9ec6d32830a0..90bd398d48f9 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyDeprecated.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyDeprecated.cs @@ -8,10 +8,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies [IgnoreTestCase ("This test checks that PreserveDependency correctly issues a warning on .NET Core where it is deprecated.")] #endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] - [LogContains ("IL2033: Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated.B.Method(): PreserveDependencyAttribute is deprecated. Use DynamicDependencyAttribute instead.")] - [LogContains ("IL2033: Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated.B.SameContext(): PreserveDependencyAttribute is deprecated. Use DynamicDependencyAttribute instead.")] - [LogContains ("IL2033: Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated.B.Broken(): PreserveDependencyAttribute is deprecated. Use DynamicDependencyAttribute instead.")] - [LogContains ("IL2033: Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated.B.Conditional(): PreserveDependencyAttribute is deprecated. Use DynamicDependencyAttribute instead.")] class PreserveDependencyDeprecated { public static void Main () @@ -45,6 +41,7 @@ void Method2 (out sbyte arg) [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated+Nested")] // Dependency on a property itself should be expressed as a dependency on one or both accessor methods [PreserveDependency ("get_Property()", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] + [ExpectedWarning ("IL2033")] public static void Method () { } @@ -52,6 +49,7 @@ public static void Method () [Kept] [PreserveDependency ("field")] [PreserveDependency ("Method2 (System.SByte&)")] + [ExpectedWarning ("IL2033")] public static void SameContext () { } @@ -63,12 +61,14 @@ public static void SameContext () [PreserveDependency ("")] [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated+NestedStruct")] [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] + [ExpectedWarning ("IL2033")] public static void Broken () { } [Kept] [PreserveDependency ("ConditionalTest()", "Mono.Linker.Tests.Cases.PreserveDependencies.D", Condition = "don't have it")] + [ExpectedWarning ("IL2033")] public static void Conditional () { } diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyErrorCases.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyErrorCases.cs new file mode 100644 index 000000000000..2adca1e4e137 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyErrorCases.cs @@ -0,0 +1,40 @@ +using System; +using System.Runtime.CompilerServices; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.PreserveDependencies +{ + [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] + [SetupLinkerArgument ("--skip-unresolved", "true")] + class PreserveDependencyErrorCases + { + public static void Main () + { + UnresolvedAssembly (); + UnresolvedType (); + UnresolvedMember (); + } + + [Kept] + [PreserveDependency ("*", "TypeName", "UnresolvedAssembly_AssemblyName")] + [ExpectedWarning ("IL2003", "UnresolvedAssembly_AssemblyName")] + static void UnresolvedAssembly () + { + } + + [Kept] + [PreserveDependency ("*", "UnresolvedType_TypeName")] + [ExpectedWarning ("IL2004", "UnresolvedType_TypeName")] + static void UnresolvedType () + { + } + + [Kept] + [PreserveDependency ("UnresolvedMember_MemberName")] + [ExpectedWarning ("IL2005", "UnresolvedMember_MemberName")] + static void UnresolvedMember () + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs index 32a6c3179426..e4a23ffa5b52 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs @@ -5,7 +5,7 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] - [LogContains ("Could not resolve 'Mono.Linker.Tests.Cases.PreserveDependencies.MissingType' type dependency")] + [LogContains ("Could not resolve dependency type 'Mono.Linker.Tests.Cases.PreserveDependencies.MissingType'")] [LogContains ("Could not resolve dependency member 'MissingMethod' declared in type 'Mono.Linker.Tests.Cases.PreserveDependencies.C'")] [LogContains ("Could not resolve dependency member 'Dependency2`1' declared in type 'Mono.Linker.Tests.Cases.PreserveDependencies.C'")] [LogContains ("Could not resolve dependency member '' declared in type 'Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod.B'")] diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs index bf62557d884b..b725e109b6ff 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs @@ -45,6 +45,7 @@ public static void Main () UnsupportedCreateInstance (); + TestCreateInstanceOfTWithConcreteType (); TestCreateInstanceOfTWithNewConstraint (); TestCreateInstanceOfTWithNoConstraint (); @@ -132,8 +133,8 @@ public FromParameterOnStaticMethodTypeB () { } public FromParameterOnStaticMethodTypeB (int arg) { } } - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (object[]) })] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo) })] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (object[]) }, messageCode: "IL2067")] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo) }, messageCode: "IL2067")] [Kept] private void FromParameterOnInstanceMethod ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] @@ -155,8 +156,8 @@ public FromParameterOnInstanceMethodType (int arg) { } public FromParameterOnInstanceMethodType (int arg, int arg2) { } } - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (object[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type) }, messageCode: "IL2067")] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (object[]) }, messageCode: "IL2067")] [Kept] private static void FromParameterWithNonPublicConstructors ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] @@ -179,7 +180,7 @@ public FromParameterWithNonPublicConstructorsType (int arg) { } private FromParameterWithNonPublicConstructorsType (int arg, int arg2) { } } - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo) })] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (Type), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo) }, messageCode: "IL2067")] [Kept] private static void FromParameterWithPublicConstructors ( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] @@ -274,34 +275,37 @@ private static void WithAssemblyName () } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string) }, + messageCode: "IL2032", message: "assemblyName")] private static void WithNullAssemblyName () { Activator.CreateInstance (null, "Mono.Linker.Tests.Cases.Reflection.ActivatorCreateInstance+WithAssemblyNameParameterless1"); } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string) }, + messageCode: "IL2061", message: "NonExistingAssembly")] private static void WithNonExistingAssemblyName () { - Activator.CreateInstance ("NonExisting", "Mono.Linker.Tests.Cases.Reflection.ActivatorCreateInstance+WithAssemblyNameParameterless1"); + Activator.CreateInstance ("NonExistingAssembly", "Mono.Linker.Tests.Cases.Reflection.ActivatorCreateInstance+WithAssemblyNameParameterless1"); } [Kept] private static string _typeNameField; [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string), typeof (object[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string), typeof (object[]) }, + messageCode: "IL2032", message: "typeName")] private static void WithAssemblyAndUnknownTypeName () { Activator.CreateInstance ("test", _typeNameField, new object[] { }); } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance), new Type[] { typeof (string), typeof (string), typeof (object[]) })] + [RecognizedReflectionAccessPattern] private static void WithAssemblyAndNonExistingTypeName () { - Activator.CreateInstance ("test", "NonExisting", new object[] { }); + Activator.CreateInstance ("test", "NonExistingType", new object[] { }); } [Kept] @@ -356,18 +360,34 @@ private static void AppDomainCreateInstance () } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "", new Type[0])] - [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string) })] - [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool) })] - [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo), typeof (object[]) })] + [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string) }, messageCode: "IL2058")] + [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool) }, messageCode: "IL2058")] + [UnrecognizedReflectionAccessPattern (typeof (Assembly), nameof (Assembly.CreateInstance), new Type[] { typeof (string), typeof (bool), typeof (BindingFlags), typeof (Binder), typeof (object[]), typeof (CultureInfo), typeof (object[]) }, messageCode: "IL2058")] private static void UnsupportedCreateInstance () { - Activator.CreateInstance (); - typeof (ActivatorCreateInstance).Assembly.CreateInstance ("NonExistent"); typeof (ActivatorCreateInstance).Assembly.CreateInstance ("NonExistent", ignoreCase: false); typeof (ActivatorCreateInstance).Assembly.CreateInstance ("NonExistent", false, BindingFlags.Public, null, new object[] { }, null, new object[] { }); + } + + [Kept] + class TestCreateInstanceOfTWithConcreteTypeType + { + [Kept] + public TestCreateInstanceOfTWithConcreteTypeType () + { + } + + public TestCreateInstanceOfTWithConcreteTypeType (int i) + { + } + } + [Kept] + [RecognizedReflectionAccessPattern] + private static void TestCreateInstanceOfTWithConcreteType () + { + Activator.CreateInstance (); } [Kept] @@ -403,7 +423,7 @@ public TestCreateInstanceOfTWithNoConstraintType (int i) } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "", new Type[0])] + [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "", new Type[0], messageCode: "IL2091")] private static void TestCreateInstanceOfTWithNoConstraint () { Activator.CreateInstance (); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs index 2874f2119e7c..4a4433d40bec 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs @@ -61,11 +61,8 @@ static Type FindType () return null; } - [UnrecognizedReflectionAccessPattern ( - typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (Type[]) }, - "The return value of method 'Mono.Linker.Tests.Cases.Reflection.ConstructorUsedViaReflection.FindType()' with dynamically accessed member kinds 'None' " + - "is passed into the implicit 'this' parameter of method 'System.Type.GetConstructor(Type[])' which requires dynamically accessed member kinds 'PublicParameterlessConstructor'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicParameterlessConstructor'.")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (Type[]) }, + messageCode: "IL2075", message: new string[] { "FindType", "GetConstructor" })] [Kept] static void TestDataFlowType () { diff --git a/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs index 41cb2fa14ba5..cf3ca4b81987 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs @@ -95,11 +95,8 @@ static Type FindType () } [Kept] - [UnrecognizedReflectionAccessPattern ( - typeof (Type), nameof (Type.GetEvent), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.Reflection.EventUsedViaReflection.FindType()' with dynamically accessed member kinds 'None' " + - "is passed into the implicit 'this' parameter of method 'System.Type.GetEvent(String)' which requires dynamically accessed member kinds 'PublicEvents'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicEvents'.")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetEvent), new Type[] { typeof (string) }, + messageCode: "IL2075", message: new string[] { "FindType", "GetEvent" })] static void TestDataFlowType () { Type type = FindType (); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs index 9b46b9af87c6..9b25f05b294c 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs @@ -56,7 +56,7 @@ private static void PrivateMethod () [Kept] [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.Call), - new Type[] { typeof (Type), typeof (string), typeof (Type[]), typeof (Expression[]) })] + new Type[] { typeof (Type), typeof (string), typeof (Type[]), typeof (Expression[]) }, messageCode: "IL2072")] public static void Test () { // Keep all methods of the type that made the call diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index 857a76f12bd0..0a6959ce82a5 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Reflection public class ExpressionFieldString { [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.Field), - new Type[] { typeof (Expression), typeof (Type), typeof (string) })] + new Type[] { typeof (Expression), typeof (Type), typeof (string) }, messageCode: "IL2072")] public static void Main () { Expression.Field (Expression.Parameter (typeof (int), ""), typeof (ExpressionFieldString), "Field"); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs index a4ed52c76c64..65e8c4a78269 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs @@ -50,15 +50,15 @@ static void Branch_SystemTypeValueNode (int i) #endregion #region UnrecognizedReflectionAccessPatterns - [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) }, messageCode: "IL2067")] [Kept] static void Branch_MethodParameterValueNode (Type T) { Expression.New (T); } - [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) })] - [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) }, messageCode: "IL2072")] + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) }, messageCode: "IL2072")] [Kept] static void Branch_UnrecognizedPatterns () { diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index fc6584a0191c..35d7b9eacdba 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -12,7 +12,7 @@ namespace Mono.Linker.Tests.Cases.Reflection public class ExpressionPropertyString { [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.Property), - new Type[] { typeof (Expression), typeof (Type), typeof (string) })] + new Type[] { typeof (Expression), typeof (Type), typeof (string) }, messageCode: "IL2072")] public static void Main () { Expression.Property (Expression.Parameter (typeof (int), ""), typeof (ExpressionPropertyString), "Property"); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs index d09773c894fd..715a73156eb1 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs @@ -91,11 +91,8 @@ static Type FindType () } [Kept] - [UnrecognizedReflectionAccessPattern ( - typeof (Type), nameof (Type.GetField), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.Reflection.FieldUsedViaReflection.FindType()' with dynamically accessed member kinds 'None' " + - "is passed into the implicit 'this' parameter of method 'System.Type.GetField(String)' which requires dynamically accessed member kinds 'PublicFields'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicFields'.")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetField), new Type[] { typeof (string) }, + messageCode: "IL2075", message: new string[] { "FindType", "GetField" })] static void TestDataFlowType () { Type type = FindType (); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs index ce2ef6e87a94..ee8c04bd75fd 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs @@ -149,11 +149,8 @@ static Type FindType () } [Kept] - [UnrecognizedReflectionAccessPattern ( - typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string), typeof (BindingFlags) }, - "The return value of method 'Mono.Linker.Tests.Cases.Reflection.MethodUsedViaReflection.FindType()' with dynamically accessed member kinds 'None' " + - "is passed into the implicit 'this' parameter of method 'System.Type.GetMethod(String,BindingFlags)' which requires dynamically accessed member kinds 'PublicMethods'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicMethods'.")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string), typeof (BindingFlags) }, + messageCode: "IL2075", message: new string[] { "FindType", "GetMethod" })] static void TestDataFlowType () { Type type = FindType (); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs b/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs index aec0d004fc0e..478de630e04d 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs @@ -25,7 +25,7 @@ static void TestSealed () } [Kept] - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetMethod), new Type[] { typeof (string) }, messageCode: "IL2075")] static void TestUnsealed () { s_unsealedClassField = new UnsealedClass (); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs index 26e569d07ac6..f4d45f25458e 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs @@ -96,11 +96,8 @@ static Type FindType () } [Kept] - [UnrecognizedReflectionAccessPattern ( - typeof (Type), nameof (Type.GetProperty), new Type[] { typeof (string) }, - "The return value of method 'Mono.Linker.Tests.Cases.Reflection.PropertyUsedViaReflection.FindType()' with dynamically accessed member kinds 'None' " + - "is passed into the implicit 'this' parameter of method 'System.Type.GetProperty(String)' which requires dynamically accessed member kinds 'PublicProperties'. " + - "To fix this add DynamicallyAccessedMembersAttribute to it and specify at least these member kinds 'PublicProperties'.")] + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetProperty), new Type[] { typeof (string) }, + messageCode: "IL2075", message: new string[] { "FindType", "GetProperty" })] static void TestDataFlowType () { Type type = FindType (); diff --git a/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs index 653ee01e062b..18df634f51d9 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/RunClassConstructorUsedViaReflection.cs @@ -48,9 +48,7 @@ static Type FindType () [Kept] [UnrecognizedReflectionAccessPattern (typeof (RuntimeHelpers), nameof (RuntimeHelpers.RunClassConstructor), new Type[] { typeof (RuntimeTypeHandle) }, - "A value from unknown source is passed into the parameter 'type' of method " + - "'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(RuntimeTypeHandle)'. " + - "It's not possible to guarantee availability of the target static constructor.")] + messageCode: "IL2059", message: "RunClassConstructor")] static void TestDataFlowType () { @@ -61,9 +59,7 @@ static void TestDataFlowType () [Kept] [RecognizedReflectionAccessPattern] [UnrecognizedReflectionAccessPattern (typeof (RuntimeHelpers), nameof (RuntimeHelpers.RunClassConstructor), new Type[] { typeof (RuntimeTypeHandle) }, - "A value from unknown source is passed into the parameter 'type' of method " + - "'System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(RuntimeTypeHandle)'. " + - "It's not possible to guarantee availability of the target static constructor.")] + messageCode: "IL2059")] static void TestIfElseUsingRuntimeTypeHandle (int i) { diff --git a/test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs b/test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs index 467650f51352..21bc8f937adc 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/RuntimeReflectionExtensionsCalls.cs @@ -20,7 +20,7 @@ public static void Main () #region GetRuntimeEvent [Kept] [UnrecognizedReflectionAccessPattern (typeof (RuntimeReflectionExtensions), nameof (RuntimeReflectionExtensions.GetRuntimeEvent), - new Type[] { typeof (Type), typeof (string) })] + new Type[] { typeof (Type), typeof (string) }, messageCode: "IL2072")] public static void TestGetRuntimeEvent () { typeof (ClassWithKeptMembers).GetRuntimeEvent ("PublicEvent"); @@ -35,7 +35,7 @@ public static void TestGetRuntimeEvent () #region GetRuntimeField [Kept] [UnrecognizedReflectionAccessPattern (typeof (RuntimeReflectionExtensions), nameof (RuntimeReflectionExtensions.GetRuntimeField), - new Type[] { typeof (Type), typeof (string) })] + new Type[] { typeof (Type), typeof (string) }, messageCode: "IL2072")] public static void TestGetRuntimeField () { typeof (ClassWithKeptMembers).GetRuntimeField ("PublicField"); @@ -50,7 +50,7 @@ public static void TestGetRuntimeField () #region GetRuntimeMethod [Kept] [UnrecognizedReflectionAccessPattern (typeof (RuntimeReflectionExtensions), nameof (RuntimeReflectionExtensions.GetRuntimeMethod), - new Type[] { typeof (Type), typeof (string), typeof (Type[]) })] + new Type[] { typeof (Type), typeof (string), typeof (Type[]) }, messageCode: "IL2072")] public static void TestGetRuntimeMethod () { typeof (ClassWithKeptMembers).GetRuntimeMethod ("PublicMethod", Type.EmptyTypes); @@ -65,7 +65,7 @@ public static void TestGetRuntimeMethod () #region GetRuntimeProperty [Kept] [UnrecognizedReflectionAccessPattern (typeof (RuntimeReflectionExtensions), nameof (RuntimeReflectionExtensions.GetRuntimeProperty), - new Type[] { typeof (Type), typeof (string) })] + new Type[] { typeof (Type), typeof (string) }, messageCode: "IL2072")] public static void TestGetRuntimeProperty () { typeof (ClassWithKeptMembers).GetRuntimeProperty ("PublicProperty"); diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.attributes.xml b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.attributes.xml new file mode 100644 index 000000000000..a42dea42fe0c --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.attributes.xml @@ -0,0 +1,12 @@ + + + + + + + Message for MethodWithDuplicateRequiresAttribute from link attributes XML + + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs index 4600388db81c..03cd6c737db2 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs @@ -7,9 +7,11 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; namespace Mono.Linker.Tests.Cases.RequiresCapability { + [SetupLinkAttributesFile ("RequiresUnreferencedCodeCapability.attributes.xml")] [SkipKeptItemsValidation] public class RequiresUnreferencedCodeCapability { @@ -20,10 +22,10 @@ public static void Main () TestRequiresOnConstructor (); TestRequiresOnPropertyGetterAndSetter (); TestRequiresSuppressesWarningsFromReflectionAnalysis (); + TestDuplicateRequiresAttribute (); } - [LogContains ( - "warning IL2026: Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.TestRequiresWithMessageOnlyOnMethod(): " + + [ExpectedWarning ("IL2026", "Calling 'Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.RequiresWithMessageOnly()' " + "which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. " + "Message for --RequiresWithMessageOnly--.")] @@ -37,8 +39,7 @@ static void RequiresWithMessageOnly () { } - [LogContains ( - "warning IL2026: Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.TestRequiresWithMessageAndUrlOnMethod(): " + + [ExpectedWarning ("IL2026", "Calling 'Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.RequiresWithMessageAndUrl()' " + "which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. " + "Message for --RequiresWithMessageAndUrl--. " + @@ -71,13 +72,11 @@ public ConstructorRequires () } } - [LogContains ( - "warning IL2026: Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.TestRequiresOnPropertyGetterAndSetter(): " + + [ExpectedWarning ("IL2026", "Calling 'Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.get_PropertyRequires()' " + "which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. " + "Message for --getter PropertyRequires--.")] - [LogContains ( - "warning IL2026: Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.TestRequiresOnPropertyGetterAndSetter(): " + + [ExpectedWarning ("IL2026", "Calling 'Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.set_PropertyRequires(Int32)' " + "which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. " + "Message for --setter PropertyRequires--.")] @@ -95,8 +94,7 @@ static int PropertyRequires { set { } } - [LogContains ( - "warning IL2026: Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.TestRequiresSuppressesWarningsFromReflectionAnalysis(): " + + [ExpectedWarning ("IL2026", "Calling 'Mono.Linker.Tests.Cases.RequiresCapability.RequiresUnreferencedCodeCapability.RequiresAndCallsOtherRequiresMethods()' " + "which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. " + "Message for --RequiresAndCallsOtherRequiresMethods--.")] @@ -144,5 +142,19 @@ public static void Method () { } static void MethodRequiresPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> () { } class TestType { } + + [ExpectedWarning ("IL2026", "--MethodWithDuplicateRequiresAttribute--")] + [LogDoesNotContain ("Message for MethodWithDuplicateRequiresAttribute from link attributes XML")] + static void TestDuplicateRequiresAttribute () + { + MethodWithDuplicateRequiresAttribute (); + } + + // The second attribute is added through link attribute XML + [RequiresUnreferencedCode ("Message for --MethodWithDuplicateRequiresAttribute--")] + [ExpectedWarning ("IL2027", "RequiresUnreferencedCodeAttribute", nameof (MethodWithDuplicateRequiresAttribute))] + static void MethodWithDuplicateRequiresAttribute () + { + } } } \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs b/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs index 8611d2a4b92b..9bdf9075dae9 100644 --- a/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs +++ b/test/Mono.Linker.Tests.Cases/Substitutions/ResourceSubstitutions.cs @@ -5,9 +5,9 @@ namespace Mono.Linker.Tests.Cases.Substitutions { [SetupLinkerSubstitutionFile ("ResourceSubstitutions.xml")] [SetupCompileResource ("Dependencies/ResourceFile.txt", "ResourceFile.txt")] - [LogContains ("IL2038: Missing 'name' attribute for resource")] - [LogContains ("IL2039: Invalid 'action' attribute for resource 'ResourceFile.txt'")] - [LogContains ("IL2040: Could not find embedded resource 'MissingResourceFile.txt' to remove in assembly 'test'")] + [ExpectedWarning ("IL2038", FileName = "ResourceSubstitutions.xml")] + [ExpectedWarning ("IL2039", "''", "ResourceFile.txt", FileName = "ResourceSubstitutions.xml")] + [ExpectedWarning ("IL2040", "MissingResourceFile.txt", "test", FileName = "ResourceSubstitutions.xml")] [RemovedResourceInAssembly ("test.exe", "ResourceFile.txt")] public class ResourceSubstitutions { diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs new file mode 100644 index 000000000000..1789eb9634d4 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs @@ -0,0 +1,41 @@ +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Substitutions +{ + [SetupLinkerSubstitutionFile ("SubstitutionsErrorCases.xml")] + + [ExpectedWarning ("IL2010", "TestMethod_1", "stub", FileName = "SubstitutionsErrorCases.xml")] + [ExpectedWarning ("IL2011", "TestMethod_2", "noaction", FileName = "SubstitutionsErrorCases.xml")] + [ExpectedWarning ("IL2013", "SubstitutionsErrorCases::InstanceField", FileName = "SubstitutionsErrorCases.xml")] + [ExpectedWarning ("IL2014", "SubstitutionsErrorCases::IntField", FileName = "SubstitutionsErrorCases.xml")] + [ExpectedWarning ("IL2015", "SubstitutionsErrorCases::IntField", "NonNumber", FileName = "SubstitutionsErrorCases.xml")] + [ExpectedWarning ("IL2007", "NonExistentAssembly", FileName = "SubstitutionsErrorCases.xml")] + + [KeptMember (".ctor()")] + class SubstitutionsErrorCases + { + public static void Main () + { + TestMethod_1 (); + TestMethod_2 (); + + var instance = new SubstitutionsErrorCases (); + instance.InstanceField = 42; + IntField = 42; + } + + [Kept] + public static int TestMethod_1 () { return 42; } + + [Kept] + public static int TestMethod_2 () { return 42; } + + [Kept] + public int InstanceField; + + [Kept] + public static int IntField; + } +} diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml new file mode 100644 index 000000000000..272ccbc30af3 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Warnings/CanDisableWarnings.cs b/test/Mono.Linker.Tests.Cases/Warnings/CanDisableWarnings.cs index 45c2c57b86e4..27f6241610fa 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/CanDisableWarnings.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/CanDisableWarnings.cs @@ -9,7 +9,7 @@ namespace Mono.Linker.Tests.Cases.Warnings [SkipKeptItemsValidation] [SetupLinkerSubstitutionFile ("CanDisableWarningsSubstitutions.xml")] [SetupLinkerArgument ("--verbose")] - [SetupLinkerArgument ("--nowarn", "IL2006,IL2007;IL2008;IL2009,IL2010,ThisWillBeIgnored")] + [SetupLinkerArgument ("--nowarn", "IL2067,IL2007;IL2008;IL2009,IL2010,ThisWillBeIgnored")] [SetupLinkerArgument ("--nowarn", "IL2011,2012,0123")] [LogDoesNotContain ("IL20(06|07|08|09|10|11)")] [LogContains ("IL2012")] diff --git a/test/Mono.Linker.Tests.Cases/Warnings/CanNotWarnAsErrorForDisabledVersion.cs b/test/Mono.Linker.Tests.Cases/Warnings/CanNotWarnAsErrorForDisabledVersion.cs index a65d49d4a196..88c933039bf0 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/CanNotWarnAsErrorForDisabledVersion.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/CanNotWarnAsErrorForDisabledVersion.cs @@ -11,7 +11,7 @@ namespace Mono.Linker.Tests.Cases.Warnings [SetupLinkerArgument ("--verbose")] [SetupLinkerArgument ("--warnaserror")] [SetupLinkerArgument ("--warn", "0")] - [LogDoesNotContain ("IL2006")] + [LogDoesNotContain ("IL2067")] public class CanNotWarnAsErrorForDisabledVersion { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion0.cs b/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion0.cs index 008b1434a182..e5457f5c4cda 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion0.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion0.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Warnings [SkipKeptItemsValidation] [SetupLinkerArgument ("--verbose")] [SetupLinkerArgument ("--warn", "0")] - [LogDoesNotContain ("IL2006")] + [LogDoesNotContain ("IL2067")] public class CanSetWarningVersion0 { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion5.cs b/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion5.cs index 7ea09553adb3..fdff415aa3ca 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion5.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion5.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Warnings [SkipKeptItemsValidation] [SetupLinkerArgument ("--verbose")] [SetupLinkerArgument ("--warn", "5")] - [LogContains ("IL2006")] + [LogContains ("IL2075")] public class CanSetWarningVersion5 { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion9999.cs b/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion9999.cs index d8f8bc1df25d..476f67dcd5be 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion9999.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/CanSetWarningVersion9999.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Warnings [SkipKeptItemsValidation] [SetupLinkerArgument ("--verbose")] [SetupLinkerArgument ("--warn", "9999")] - [LogContains ("IL2006")] + [LogContains ("IL2075")] public class CanSetWarningVersion9999 { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs index 681a36075b13..bdf95bbc62e7 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/AddSuppressionsBeforeAttributeRemoval.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression { [SkipKeptItemsValidation] [SetupLinkAttributesFile ("AddSuppressionsBeforeAttributeRemoval.xml")] - [LogDoesNotContain ("IL2006: Mono.Linker.Tests.Cases.Warnings.WarningSuppression.AddSuppressionsBeforeAttributeRemoval.Main()")] + [LogDoesNotContain ("IL2067: Mono.Linker.Tests.Cases.Warnings.WarningSuppression.AddSuppressionsBeforeAttributeRemoval.Main()")] public class AddSuppressionsBeforeAttributeRemoval { public static Type TriggerUnrecognizedPattern () @@ -18,7 +18,7 @@ public static Type TriggerUnrecognizedPattern () return typeof (AddedPseudoAttributeAttribute); } - [UnconditionalSuppressMessage ("ILLinker", "IL2006")] + [UnconditionalSuppressMessage ("ILLinker", "IL2067")] public static void Main () { Expression.Call (TriggerUnrecognizedPattern (), "", Type.EmptyTypes); diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInAssembly.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInAssembly.cs index a7a032f1b4a9..e37f800e3e94 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInAssembly.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; -[assembly: UnconditionalSuppressMessage ("Test", "IL2006:Suppress unrecognized reflection pattern warnings in this assembly")] +[assembly: UnconditionalSuppressMessage ("Test", "IL2072:Suppress unrecognized reflection pattern warnings in this assembly")] namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression { diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypes.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypes.cs index 7e386ce9d3b0..7499df8b35fb 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypes.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypes.cs @@ -35,7 +35,7 @@ public static Type TriggerUnrecognizedPattern () return typeof (SuppressWarningsInMembersAndTypes); } - [UnconditionalSuppressMessage ("Test", "IL2006:Suppress UnrecognizedReflectionPattern warnings on a nested type")] + [UnconditionalSuppressMessage ("Test", "IL2072:Suppress UnrecognizedReflectionPattern warnings on a nested type")] public class NestedType { public static void Warning () @@ -45,7 +45,7 @@ public static void Warning () } } - [UnconditionalSuppressMessage ("Test", "IL2006:UnrecognizedReflectionPattern")] + [UnconditionalSuppressMessage ("Test", "IL2072:UnrecognizedReflectionPattern")] public class SuppressWarningsInType { public void Warning1 () @@ -75,13 +75,13 @@ void Warning4 () public class SuppressWarningsInMembers { - [UnconditionalSuppressMessage ("Test", "IL2006:UnrecognizedReflectionPattern")] + [UnconditionalSuppressMessage ("Test", "IL2072:UnrecognizedReflectionPattern")] public void Method () { Expression.Call (SuppressWarningsInMembersAndTypes.TriggerUnrecognizedPattern (), "", Type.EmptyTypes); } - [UnconditionalSuppressMessage ("Test", "IL2006:Suppression with scope value equal to null", + [UnconditionalSuppressMessage ("Test", "IL2072:Suppression with scope value equal to null", Scope = null, Target = null, MessageId = null)] @@ -91,7 +91,7 @@ public void SuppressionHasNullParameters () } public int Property { - [UnconditionalSuppressMessage ("Test", "IL2006:UnrecognizedReflectionPattern")] + [UnconditionalSuppressMessage ("Test", "IL2072:UnrecognizedReflectionPattern")] get { Expression.Call (SuppressWarningsInMembersAndTypes.TriggerUnrecognizedPattern (), "", Type.EmptyTypes); return 0; diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypesUsingTarget.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypesUsingTarget.cs index 68d3a9b80346..1da20c511d09 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypesUsingTarget.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInMembersAndTypesUsingTarget.cs @@ -5,9 +5,9 @@ using System.Linq.Expressions; using System.Text; -[module: UnconditionalSuppressMessage ("Test", "IL2006", Scope = "type", Target = "T:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.WarningsInType")] -[module: UnconditionalSuppressMessage ("Test", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.WarningsInMembers.Method")] -[module: UnconditionalSuppressMessage ("Test", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.WarningsInMembers.get_Property")] +[module: UnconditionalSuppressMessage ("Test", "IL2072", Scope = "type", Target = "T:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.WarningsInType")] +[module: UnconditionalSuppressMessage ("Test", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.WarningsInMembers.Method")] +[module: UnconditionalSuppressMessage ("Test", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.WarningsInMembers.get_Property")] namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression { diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInModule.cs b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInModule.cs index ccd2021a5193..5c0a38fb8650 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInModule.cs +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsInModule.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; -[module: UnconditionalSuppressMessage ("Test", "IL2006:Suppress unrecognized reflection pattern warnings in this module")] +[module: UnconditionalSuppressMessage ("Test", "IL2072:Suppress unrecognized reflection pattern warnings in this module")] namespace Mono.Linker.Tests.Cases.Warnings.WarningSuppression { diff --git a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsUsingTargetViaXml.xml b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsUsingTargetViaXml.xml index d8cf0bfd04ae..84d34f02f2cb 100644 --- a/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsUsingTargetViaXml.xml +++ b/test/Mono.Linker.Tests.Cases/Warnings/WarningSuppression/SuppressWarningsUsingTargetViaXml.xml @@ -3,31 +3,31 @@ ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Main ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning3 ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning4``1(System.Collections.Generic.List{``0}@) ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Warning1 ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.get_Warning2 diff --git a/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs b/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs index ad0a3bcda01d..598d28789484 100644 --- a/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs +++ b/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs @@ -150,5 +150,19 @@ public static string GetSignature (this MethodDefinition method) return builder.ToString (); } + + public static object GetConstructorArgumentValue (this CustomAttribute attr, int argumentIndex) + { + return attr.ConstructorArguments[argumentIndex].Value; + } + + public static object GetPropertyValue (this CustomAttribute attr, string propertyName) + { + foreach (var prop in attr.Properties) + if (prop.Name == propertyName) + return prop.Argument.Value; + + return null; + } } } \ No newline at end of file diff --git a/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations1.cs b/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations1.cs index ffb57f2c5f87..b76a941d5667 100644 --- a/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations1.cs +++ b/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations1.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.get_Warning2")] -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.NestedType.Warning3")] -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.NestedType.Warning4``1(System.Collections.Generic.List{``0}@)")] -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.Warning1")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.get_Warning2")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.NestedType.Warning3")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.NestedType.Warning4``1(System.Collections.Generic.List{``0}@)")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Warnings.Warning1")] diff --git a/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations2.cs b/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations2.cs index c5044a3650c2..2be1eb90bee8 100644 --- a/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations2.cs +++ b/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations2.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.get_Warning2")] -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Main")] -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning3")] -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning4``1(System.Collections.Generic.List{``0}@)")] -[assembly: UnconditionalSuppressMessage ("ILLink", "IL2006", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Warning1")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.get_Warning2")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Main")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning3")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning4``1(System.Collections.Generic.List{``0}@)")] +[assembly: UnconditionalSuppressMessage ("ILLink", "IL2072", Scope = "member", Target = "M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Warning1")] diff --git a/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations3.xml b/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations3.xml index eea6cbf6ad9a..f8fb6fe2422c 100644 --- a/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations3.xml +++ b/test/Mono.Linker.Tests/TestCases/Dependencies/WarningSuppressionExpectations3.xml @@ -3,31 +3,31 @@ ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.get_Warning2 ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Main ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning3 ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.NestedType.Warning4``1(System.Collections.Generic.List{``0}@) ILLink - IL2006 + IL2072 member M:Mono.Linker.Tests.Cases.Warnings.WarningSuppression.Dependencies.TriggerWarnings_Lib.Warning1 diff --git a/test/Mono.Linker.Tests/TestCasesRunner/LinkerTestLogger.cs b/test/Mono.Linker.Tests/TestCasesRunner/LinkerTestLogger.cs index f2789c82da1a..5e28a68aac4b 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/LinkerTestLogger.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/LinkerTestLogger.cs @@ -7,14 +7,22 @@ public class LinkerTestLogger : ILogger public struct MessageRecord { public string Message; + public MessageCategory Category; + public MessageOrigin? Origin; + public int? Code; + public string Text; } public List Messages { get; private set; } = new List (); public void LogMessage (MessageContainer msBuildMessage) { - Messages.Add (new MessageRecord { - Message = msBuildMessage.ToString () + Messages.Add (new MessageRecord () { + Message = msBuildMessage.ToString (), + Category = msBuildMessage.Category, + Origin = msBuildMessage.Origin, + Code = msBuildMessage.Code, + Text = msBuildMessage.Text }); } } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index 77fa07f28c5d..44ad7cac7e93 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -595,36 +595,92 @@ void VerifyKeptAllTypesAndMembersInAssembly (AssemblyDefinition linked) void VerifyLoggedMessages (AssemblyDefinition original, LinkerTestLogger logger) { foreach (var testType in original.AllDefinedTypes ()) { - foreach (var attr in testType.CustomAttributes.Concat (testType.AllMembers ().SelectMany (m => m.CustomAttributes))) { - if (attr.AttributeType.Resolve ().Name == nameof (LogContainsAttribute)) { - var expectedMessage = (string) attr.ConstructorArguments[0].Value; - - List matchedMessages; - if ((bool) attr.ConstructorArguments[1].Value) - matchedMessages = logger.Messages.Where (mc => Regex.IsMatch (mc.Message, expectedMessage)).ToList (); - else - matchedMessages = logger.Messages.Where (mc => mc.Message.Contains (expectedMessage)).ToList (); ; - Assert.IsTrue ( - matchedMessages.Count > 0, - $"Expected to find logged message matching `{expectedMessage}`, but no such message was found.{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, logger.Messages.Select (mc => mc.Message))}"); - - foreach (var matchedMessage in matchedMessages) - logger.Messages.Remove (matchedMessage); - } + foreach (var attrProvider in testType.AllMembers ().Append (testType)) { + foreach (var attr in attrProvider.CustomAttributes) { + switch (attr.AttributeType.Name) { + + case nameof (LogContainsAttribute): { + var expectedMessage = (string) attr.ConstructorArguments[0].Value; - if (attr.AttributeType.Resolve ().Name == nameof (LogDoesNotContainAttribute)) { - var unexpectedMessage = (string) attr.ConstructorArguments[0].Value; - foreach (var loggedMessage in logger.Messages) { - Assert.That (() => { + List matchedMessages; if ((bool) attr.ConstructorArguments[1].Value) - return !Regex.IsMatch (loggedMessage.Message, unexpectedMessage); - return !Regex.IsMatch (loggedMessage.Message, unexpectedMessage); - }, - $"Expected to not find logged message matching `{unexpectedMessage}`, but found:{Environment.NewLine}{loggedMessage.Message}{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, logger.Messages.Select (mc => mc.Message))}"); + matchedMessages = logger.Messages.Where (mc => Regex.IsMatch (mc.Message, expectedMessage)).ToList (); + else + matchedMessages = logger.Messages.Where (mc => mc.Message.Contains (expectedMessage)).ToList (); ; + Assert.IsTrue ( + matchedMessages.Count > 0, + $"Expected to find logged message matching `{expectedMessage}`, but no such message was found.{Environment.NewLine}Logged messages:{Environment.NewLine}{FormatAllMessages ()}"); + + foreach (var matchedMessage in matchedMessages) + logger.Messages.Remove (matchedMessage); + } + break; + + case nameof (LogDoesNotContainAttribute): { + var unexpectedMessage = (string) attr.ConstructorArguments[0].Value; + foreach (var loggedMessage in logger.Messages) { + Assert.That (() => { + if ((bool) attr.ConstructorArguments[1].Value) + return !Regex.IsMatch (loggedMessage.Message, unexpectedMessage); + return !loggedMessage.Message.Contains (unexpectedMessage); + }, + $"Expected to not find logged message matching `{unexpectedMessage}`, but found:{Environment.NewLine}{loggedMessage.Message}{Environment.NewLine}Logged messages:{Environment.NewLine}{FormatAllMessages ()}"); + } + } + break; + + case nameof (ExpectedWarningAttribute): { + var expectedWarningCode = (string) attr.GetConstructorArgumentValue (0); + if (!expectedWarningCode.StartsWith ("IL")) + break; + int expectedWarningCodeNumber = int.Parse (expectedWarningCode.Substring (2)); + var expectedMessageContains = ((CustomAttributeArgument[]) attr.GetConstructorArgumentValue (1)).Select (a => (string) a.Value).ToArray (); + + string fileName = (string) attr.GetPropertyValue ("FileName"); + int? sourceLine = (int?) attr.GetPropertyValue ("SourceLine"); + int? sourceColumn = (int?) attr.GetPropertyValue ("SourceColumn"); + + var actualMethod = attrProvider as MethodDefinition; + + Assert.IsTrue ( + logger.Messages.Any (mc => { + if (mc.Category == MessageCategory.Warning && mc.Code != expectedWarningCodeNumber) + return false; + + foreach (var expectedMessage in expectedMessageContains) + if (!mc.Text.Contains (expectedMessage)) + return false; + + if (fileName != null) { + // Note: string.Compare(string, StringComparison) doesn't exist in .NET Framework API set + if (mc.Origin?.FileName?.IndexOf (fileName, StringComparison.OrdinalIgnoreCase) < 0) + return false; + + if (sourceLine != null && mc.Origin?.SourceLine != sourceLine.Value) + return false; + + if (sourceColumn != null && mc.Origin?.SourceColumn != sourceColumn.Value) + return false; + } else if (mc.Origin?.MemberDefinition?.FullName != attrProvider.FullName) + return false; + + return true; + }), + $"Expected to find warning: {(fileName != null ? (fileName + (sourceLine != null ? $"({sourceLine},{sourceColumn})" : "")) + ": " : "")}" + + $"warning {expectedWarningCode}: {(fileName == null ? (actualMethod?.GetDisplayName () ?? attrProvider.FullName) + ": " : "")}" + + $"and message containing {string.Join (" ", expectedMessageContains.Select (m => "'" + m + "'"))}, " + + $"but no such message was found.{Environment.NewLine}Logged messages:{Environment.NewLine}{FormatAllMessages ()}"); + } + break; } } } } + + string FormatAllMessages () + { + return string.Join (Environment.NewLine, logger.Messages.Select (mc => mc.Message)); + } } void VerifyRecordedDependencies (AssemblyDefinition original, TestDependencyRecorder dependencyRecorder) @@ -728,7 +784,16 @@ void VerifyRecordedReflectionPatterns (AssemblyDefinition original, TestReflecti foundAttributesToVerify = true; string expectedSourceMember = GetFullMemberNameFromDefinition (expectedSourceMemberDefinition); string expectedReflectionMember = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 0); - string expectedMessage = (string) attr.ConstructorArguments[3].Value; + string[] expectedMessageParts = GetMessagePartsFromReflectionAccessPatternAttribute (attr, 3); + int? expectedMessageCode = null; + if (attr.ConstructorArguments.Count >= 5) { + var codeString = (string) attr.ConstructorArguments[4].Value; + if (codeString != null) { + if (!codeString.StartsWith ("IL")) + throw new InvalidOperationException ($"invalid message code {codeString}"); + expectedMessageCode = int.Parse (codeString.Substring (2)); + } + } if (!reflectionPatternRecorder.UnrecognizedPatterns.Any (pattern => { if (GetFullMemberNameFromDefinition (pattern.Source) != expectedSourceMember) @@ -743,7 +808,11 @@ void VerifyRecordedReflectionPatterns (AssemblyDefinition original, TestReflecti if (actualAccessOperation != expectedReflectionMember) return false; - if (expectedMessage != null && pattern.Message != expectedMessage) + // Note: string.Compare(string, StringComparison) doesn't exist in .NET Framework API set + if (expectedMessageParts != null && expectedMessageParts.Any (p => pattern.Message.IndexOf (p, StringComparison.Ordinal) < 0)) + return false; + + if (expectedMessageCode.HasValue && pattern.MessageCode != expectedMessageCode.Value) return false; reflectionPatternRecorder.UnrecognizedPatterns.Remove (pattern); @@ -757,7 +826,9 @@ void VerifyRecordedReflectionPatterns (AssemblyDefinition original, TestReflecti .Select (p => "\t" + UnrecognizedReflectionAccessPatternToString (p))); Assert.Fail ( - $"Expected to find unrecognized reflection access pattern '{expectedSourceMember}: Usage of {expectedReflectionMember} unrecognized '{expectedMessage ?? string.Empty}''{Environment.NewLine}" + + $"Expected to find unrecognized reflection access pattern '{(expectedMessageCode == null ? "" : ("IL" + expectedMessageCode + " "))}" + + $"{expectedSourceMember}: Usage of {expectedReflectionMember} unrecognized " + + $"{(expectedMessageParts == null ? string.Empty : "and message contains " + string.Join (" ", expectedMessageParts.Select (p => "'" + p + "'")))}'{Environment.NewLine}" + $"Potential patterns matching the source member: {Environment.NewLine}{sourceMemberCandidates}{Environment.NewLine}" + $"Potential patterns matching the reflection member: {Environment.NewLine}{reflectionMemberCandidates}{Environment.NewLine}" + $"If there's no matches, try to specify just a part of the source member or reflection member name and rerun the test to get potential matches."); @@ -821,7 +892,7 @@ static string GetFullMemberNameFromReflectionAccessPatternAttribute (CustomAttri string fullName = type.ToString (); if (attr.AttributeType.Name == "UnrecognizedReflectionAccessPatternAttribute") { - var returnType = attr.ConstructorArguments[constructorArgumentsOffset + 4].Value; + var returnType = attr.ConstructorArguments[constructorArgumentsOffset + 5].Value; if (returnType != null) { fullName = fullName.Insert (0, returnType.ToString () + " "); } @@ -839,6 +910,20 @@ static string GetFullMemberNameFromReflectionAccessPatternAttribute (CustomAttri return fullName; } + static string[] GetMessagePartsFromReflectionAccessPatternAttribute (CustomAttribute attr, int messageParameterIndex) + { + var messageParameter = attr.ConstructorArguments[messageParameterIndex].Value; + if (messageParameter is CustomAttributeArgument messageAttributeArgument) + messageParameter = messageAttributeArgument.Value; + + if (messageParameter is null) + return null; + else if (messageParameter is string messagePartString) + return new string[] { messagePartString }; + else + return ((CustomAttributeArgument[]) messageParameter).Select (p => (string) p.Value).ToArray (); + } + static string GetFullMemberNameFromDefinition (IMetadataTokenProvider member) { // Method which basically returns the same as member.ToString() but without the return type @@ -908,7 +993,7 @@ static string UnrecognizedReflectionAccessPatternToString (TestReflectionPattern operationDescription = "Usage of " + GetFullMemberNameFromDefinition (instructionOperand) + " unrecognized"; } else operationDescription = "Usage of " + GetFullMemberNameFromDefinition (pattern.AccessedItem) + " unrecognized"; - return $"{GetFullMemberNameFromDefinition (pattern.Source)}: {operationDescription} '{pattern.Message}'"; + return $"IL{pattern.MessageCode} {GetFullMemberNameFromDefinition (pattern.Source)}: {operationDescription} '{pattern.Message}'"; } protected TypeDefinition GetOriginalTypeFromInAssemblyAttribute (CustomAttribute inAssemblyAttribute) diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs index dd3a9265e23a..d35deb887e88 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs @@ -14,6 +14,7 @@ public struct ReflectionAccessPattern public Instruction SourceInstruction; public IMetadataTokenProvider AccessedItem; public string Message; + public int MessageCode; } public List RecognizedPatterns = new List (); @@ -29,14 +30,15 @@ public void RecognizedReflectionAccessPattern (IMemberDefinition source, Instruc }); } - public void UnrecognizedReflectionAccessPattern (IMemberDefinition source, Instruction sourceInstruction, IMetadataTokenProvider accessedItem, string message) + public void UnrecognizedReflectionAccessPattern (IMemberDefinition source, Instruction sourceInstruction, IMetadataTokenProvider accessedItem, string message, int messageCode) { - PreviousRecorder?.UnrecognizedReflectionAccessPattern (source, sourceInstruction, accessedItem, message); + PreviousRecorder?.UnrecognizedReflectionAccessPattern (source, sourceInstruction, accessedItem, message, messageCode); UnrecognizedPatterns.Add (new ReflectionAccessPattern { Source = source, SourceInstruction = sourceInstruction, AccessedItem = accessedItem, - Message = message + Message = message, + MessageCode = messageCode }); } }