Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Boemer <sbomer@gmail.com>2021-08-26 03:08:22 +0300
committerGitHub <noreply@github.com>2021-08-26 03:08:22 +0300
commit5137d45c3adc1f2bab1642170f136e75beafca82 (patch)
treec21974c51bd8cedf624f5f08e32a568d207a1480
parent66fd7119cd5744dd8bd37442ac74d2a326085406 (diff)
Validate unrecognized patterns against logged warnings (#2230)
* Validate unrecognized patterns against logged warnings This changes the linker validation to check for unrecognized reflection access patterns against logged messages. The plan is to do the same for the analyzer tests, allowing us to make progress as we replace UnrecognizedReflectionAccessPatternAttribute with ExpectedWarningAttribute. The UnrecognizedReflectionAccessPatternAttribute is now checked against both the logged messages and recorded unrecognized reflection patterns. We check that it matches the same number of patterns as logged warnings for consistency. This required some changes to the signature formats used for validation, since the signatures used in this attribute now need to use the same format as the one we use for logged warnings. Changing the signature formats here uncovered some places where we were still using the cecil signature format even for user-visible warnings. These have been changed to use the format from GetDisplayName. Generic parameter dataflow validation treats the UnrecognizedReflectionAccessPatternAttribute differently, using the member name to refer to a generic type parameter. This inconsistency has been lifted into a separate custom attribute argument that specifies when the attribute refers to a generic parameter. Non-generic method parameters had a similar problem, but this was less common, so those usages were just replaced by ExpectedWarningAttribute. * PR feedback - Continue returning cecil signature as fallback (replace exception with a debug assert) - Remove left-over logic from debugging * Fix more tests - Use display name signature format for MethodReference - Revert changes that expect attributes to match only one warning - Remove debug output - Also add missing using
-rw-r--r--src/linker/Linker.Dataflow/DiagnosticUtilities.cs4
-rw-r--r--src/linker/Linker/MemberReferenceExtensions.cs13
-rw-r--r--test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs6
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs4
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs48
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs10
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs4
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs8
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs14
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs4
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs4
-rw-r--r--test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs32
-rw-r--r--test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs6
-rw-r--r--test/Mono.Linker.Tests/TestCases/Dependencies/SortedWarnings.txt10
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs738
15 files changed, 480 insertions, 425 deletions
diff --git a/src/linker/Linker.Dataflow/DiagnosticUtilities.cs b/src/linker/Linker.Dataflow/DiagnosticUtilities.cs
index a6fe38423..feb461903 100644
--- a/src/linker/Linker.Dataflow/DiagnosticUtilities.cs
+++ b/src/linker/Linker.Dataflow/DiagnosticUtilities.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -34,6 +34,6 @@ namespace Mono.Linker.Dataflow
genericParameter.DeclaringType.GetDisplayName ();
internal static string GetMethodSignatureDisplayName (IMethodSignature methodSignature) =>
- (methodSignature is MethodDefinition method) ? method.GetDisplayName () : methodSignature.ToString ();
+ (methodSignature is MethodReference method) ? method.GetDisplayName () : methodSignature.ToString ();
}
}
diff --git a/src/linker/Linker/MemberReferenceExtensions.cs b/src/linker/Linker/MemberReferenceExtensions.cs
index 967a4975d..b24364aaa 100644
--- a/src/linker/Linker/MemberReferenceExtensions.cs
+++ b/src/linker/Linker/MemberReferenceExtensions.cs
@@ -1,4 +1,7 @@
-using Mono.Cecil;
+using System;
+using System.Diagnostics;
+using System.Text;
+using Mono.Cecil;
namespace Mono.Linker
{
@@ -13,7 +16,15 @@ namespace Mono.Linker
case MethodReference method:
return method.GetDisplayName ();
+ case IMemberDefinition memberDef:
+ var sb = new StringBuilder ();
+ if (memberDef.DeclaringType != null)
+ sb.Append (memberDef.DeclaringType.GetDisplayName ()).Append ('.');
+ sb.Append (memberDef.Name);
+ return sb.ToString ();
+
default:
+ Debug.Assert (false, "The display name should not use cecil's signature format.");
return member.FullName;
}
}
diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs
index 7d8899712..ac0f9e54c 100644
--- a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs
+++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/UnrecognizedReflectionAccessPatternAttribute.cs
@@ -22,7 +22,8 @@ namespace Mono.Linker.Tests.Cases.Expectations.Assertions
Type[] reflectionMethodParameters,
string[] message = null,
string messageCode = null,
- Type returnType = null)
+ Type returnType = null,
+ string genericParameter = null)
{
}
@@ -32,7 +33,8 @@ namespace Mono.Linker.Tests.Cases.Expectations.Assertions
string[] reflectionMethodParameters = null,
string[] message = null,
string messageCode = null,
- Type returnType = null)
+ Type returnType = null,
+ string genericParameter = null)
{
}
}
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs
index 38c5113f2..b77d032ca 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs
@@ -41,14 +41,14 @@ namespace Mono.Linker.Tests.Cases.DataFlow
static Type s_typeWithPublicParameterlessConstructor;
[Kept]
- [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "System.Type&" }, messageCode: "IL2077")]
+ [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "Type&" }, messageCode: "IL2077")]
public static void PassRefToField ()
{
MethodWithRefParameter (ref s_typeWithPublicParameterlessConstructor);
}
[Kept]
- [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "System.Type&" }, messageCode: "IL2067")]
+ [UnrecognizedReflectionAccessPattern (typeof (ByRefDataflow), nameof (MethodWithRefParameter), new string[] { "Type&" }, messageCode: "IL2067")]
public static void PassRefToParameter (Type parameter)
{
MethodWithRefParameter (ref parameter);
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs
index 1665c1abd..357eb562c 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs
@@ -151,7 +151,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
class TypeRequiresPublicFieldsPassThrough<
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TSource>
{
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T",
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T",
messageCode: "IL2091", message: new string[] {
nameof(TSource),
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeRequiresPublicFieldsPassThrough<TSource>",
@@ -167,8 +167,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
class TypeRequiresNothingPassThrough<T>
{
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicFields<>), "T", messageCode: "IL2091")]
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicFields<>), null, genericParameter: "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")]
public static void Test ()
{
TypeRequiresPublicFields<T>.Test ();
@@ -271,10 +271,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{
}
- [UnrecognizedReflectionAccessPattern (typeof (GenericBaseTypeWithRequirements<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericBaseTypeWithRequirements<>), null, genericParameter: "T", messageCode: "IL2091")]
class DerivedTypeWithOpenGenericOnBase<T> : GenericBaseTypeWithRequirements<T>
{
- [UnrecognizedReflectionAccessPattern (typeof (GenericBaseTypeWithRequirements<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericBaseTypeWithRequirements<>), null, genericParameter: "T", messageCode: "IL2091")]
public DerivedTypeWithOpenGenericOnBase () { }
}
@@ -310,7 +310,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{
}
- [UnrecognizedReflectionAccessPattern (typeof (IGenericInterfaceTypeWithRequirements<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (IGenericInterfaceTypeWithRequirements<>), null, genericParameter: "T", messageCode: "IL2091")]
class InterfaceImplementationTypeWithOpenGenericOnBase<T> : IGenericInterfaceTypeWithRequirements<T>
{
}
@@ -376,7 +376,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[RecognizedReflectionAccessPattern]
public TypeRequiresPublicFields<TOuter> PublicFieldsField;
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")]
public TypeRequiresPublicMethods<TOuter> PublicMethodsField;
public TypeRequiresPublicFields<TOuter> PublicFieldsProperty {
@@ -387,21 +387,21 @@ namespace Mono.Linker.Tests.Cases.DataFlow
}
public TypeRequiresPublicMethods<TOuter> PublicMethodsProperty {
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")]
get => null;
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")]
set { }
}
[RecognizedReflectionAccessPattern]
public void PublicFieldsMethodParameter (TypeRequiresPublicFields<TOuter> param) { }
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")]
public void PublicMethodsMethodParameter (TypeRequiresPublicMethods<TOuter> param) { }
[RecognizedReflectionAccessPattern]
public TypeRequiresPublicFields<TOuter> PublicFieldsMethodReturnValue () { return null; }
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] // Return value
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")] // Compiler generated local variable
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")] // Return value
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")] // Compiler generated local variable
public TypeRequiresPublicMethods<TOuter> PublicMethodsMethodReturnValue () { return null; }
[RecognizedReflectionAccessPattern]
@@ -409,7 +409,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{
TypeRequiresPublicFields<TOuter> t = null;
}
- [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (TypeRequiresPublicMethods<>), null, genericParameter: "T", messageCode: "IL2091")]
public void PublicMethodsMethodLocalVariable ()
{
TypeRequiresPublicMethods<TOuter> t = null;
@@ -443,11 +443,11 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseForPartialInstantiation<,>), "TMethods", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (BaseForPartialInstantiation<,>), null, genericParameter: "TMethods", messageCode: "IL2091")]
class PartialyInstantiatedMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TOuter>
: BaseForPartialInstantiation<TestType, TOuter>
{
- [UnrecognizedReflectionAccessPattern (typeof (BaseForPartialInstantiation<,>), "TMethods", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (BaseForPartialInstantiation<,>), null, genericParameter: "TMethods", messageCode: "IL2091")]
public PartialyInstantiatedMethods () { }
}
@@ -493,7 +493,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (T).RequiresNone ();
}
- [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<#1>()::T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<T>", new Type[0] { }, genericParameter: "T", messageCode: "IL2091")]
static void MethodRequiresPublicFieldsPassThrough<
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> ()
{
@@ -502,8 +502,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
MethodRequiresNothing<T> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicFields) + "<#1>()::T", messageCode: "IL2091")]
- [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<#1>()::T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicFields) + "<T>", new Type[0] { }, genericParameter: "T", messageCode: "IL2091")]
+ [UnrecognizedReflectionAccessPattern (typeof (GenericParameterDataFlow), nameof (MethodRequiresPublicMethods) + "<T>", new Type[0] { }, genericParameter: "T", messageCode: "IL2091")]
static void MethodRequiresNothingPassThrough<T> ()
{
MethodRequiresPublicFields<T> ();
@@ -575,7 +575,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
class TypeWithInstantiatedGenericMethodViaGenericParameter<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TOuter>
: BaseTypeWithGenericMethod, IInterfaceWithGenericMethod
{
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<#1>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<T>", new Type[0] { }, genericParameter: "T",
messageCode: "IL2091", message: new string[] {
"TInner",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>.StaticRequiresPublicFields<TInner>()",
@@ -587,7 +587,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
StaticRequiresPublicMethods<TInner> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<#1>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresPublicMethods) + "<T>", new Type[0] { }, genericParameter: "T",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
@@ -605,7 +605,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
StaticRequiresMultipleGenericParams<TOuter, TestType> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams) + "<#2>()::TMethods",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.StaticRequiresMultipleGenericParams) + "<TFields,TMethods>", new Type[0] { }, genericParameter: "TMethods",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
@@ -616,7 +616,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
StaticRequiresMultipleGenericParams<TestType, TOuter> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<#1>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<T>", new Type[0] { }, genericParameter: "T",
messageCode: "IL2091", message: new string[] {
"TInner",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>.InstanceRequiresPublicFields<TInner>()",
@@ -628,7 +628,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
InstanceRequiresPublicMethods<TInner> ();
}
- [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<#1>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (BaseTypeWithGenericMethod), nameof (BaseTypeWithGenericMethod.InstanceRequiresPublicMethods) + "<T>", new Type[0] { }, genericParameter: "T",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
@@ -664,7 +664,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (T).RequiresPublicMethods ();
}
- [UnrecognizedReflectionAccessPattern (typeof (IInterfaceWithGenericMethod), nameof (IInterfaceWithGenericMethod.InterfaceRequiresPublicMethods) + "<#1>()::T",
+ [UnrecognizedReflectionAccessPattern (typeof (IInterfaceWithGenericMethod), nameof (IInterfaceWithGenericMethod.InterfaceRequiresPublicMethods) + "<T>", new Type[0] { }, genericParameter: "T",
messageCode: "IL2091", message: new string[] {
"TOuter",
"Mono.Linker.Tests.Cases.DataFlow.GenericParameterDataFlow.TypeWithInstantiatedGenericMethodViaGenericParameter<TOuter>",
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs
index 01047bc7a..bb7a69ce9 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -82,7 +82,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
RequirePublicConstructors (type);
}
- [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")]
+ [ExpectedWarning ("IL2072", "'type'", "argument", nameof (WriteToParameterOnInstanceMethod) + "(Type)", nameof (ReturnThingsWithPublicParameterlessConstructor))]
private void WriteToParameterOnInstanceMethod (
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type type)
@@ -90,7 +90,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
type = ReturnThingsWithPublicParameterlessConstructor ();
}
- [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")]
+ [ExpectedWarning ("IL2072", "'type'", "argument", nameof (WriteToParameterOnStaticMethod) + "(Type)", nameof (ReturnThingsWithPublicParameterlessConstructor))]
private static void WriteToParameterOnStaticMethod (
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
Type type)
@@ -98,7 +98,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
type = ReturnThingsWithPublicParameterlessConstructor ();
}
- [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")]
+ [ExpectedWarning ("IL2072", "'type'", "argument", nameof (LongWriteToParameterOnInstanceMethod) + "(Int32,Int32,Int32,Int32,Type)", nameof (ReturnThingsWithPublicParameterlessConstructor))]
private void LongWriteToParameterOnInstanceMethod (
int a, int b, int c, int d,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
@@ -107,7 +107,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
type = ReturnThingsWithPublicParameterlessConstructor ();
}
- [UnrecognizedReflectionAccessPattern (typeof (Type), "type", messageCode: "IL2072")]
+ [ExpectedWarning ("IL2072", "'type'", "argument", nameof (LongWriteToParameterOnStaticMethod) + "(Int32,Int32,Int32,Int32,Type)", nameof (ReturnThingsWithPublicParameterlessConstructor))]
private static void LongWriteToParameterOnStaticMethod (
int a, int b, int c, int d,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs
index 79a20fbfe..102180de2 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -237,7 +237,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
private Type PropertyWithDifferentBackingFields_SetterField;
[ExpectedWarning ("IL2042",
- "System.Type Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow/TestAutomaticPropagationType::PropertyWithDifferentBackingFields()")]
+ "Mono.Linker.Tests.Cases.DataFlow.PropertyDataFlow.TestAutomaticPropagationType.PropertyWithDifferentBackingFields")]
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
Type PropertyWithDifferentBackingFields {
get {
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
index e2b019e39..02129fb6c 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
@@ -467,11 +467,9 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[Kept]
- [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "<#1>", new Type[0], messageCode: "IL2091")]
-#if NETCOREAPP
- // Warnings are currently duplicated in NETCORE (annotation and intrinsics) - but they're not identical in this case, so we have to list both cases
- [UnrecognizedReflectionAccessPattern (typeof (Activator), nameof (Activator.CreateInstance) + "<#1>()::T", messageCode: "IL2091")]
-#endif
+ [ExpectedWarning ("IL2091", nameof (Activator), nameof (Activator.CreateInstance) + "<T>")]
+ // Warnings are currently duplicated in NETCORE (annotation and intrinsics) - but they're not identical in this case.
+ // See https://github.com/mono/linker/issues/1483
private static void TestCreateInstanceOfTWithNoConstraint<T> ()
{
Activator.CreateInstance<T> ();
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs
index 93036b120..dde8f46f9 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/ConstructorUsedViaReflection.cs
@@ -60,7 +60,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[RecognizedReflectionAccessPattern (
typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (Type[]) },
- typeof (EmptyTypes), ".ctor", new Type[0])]
+ typeof (EmptyTypes), nameof (EmptyTypes), new Type[0])]
static void TestConstructorWithTypes_EmptyTypes ()
{
var constructor = typeof (EmptyTypes).GetConstructor (new Type[] { });
@@ -125,7 +125,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[RecognizedReflectionAccessPattern (
typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (BindingFlags), typeof (Binder), typeof (Type[]), typeof (ParameterModifier[]) },
- typeof (KnownBindingFlags), ".ctor", new Type[0])]
+ typeof (KnownBindingFlags), nameof (KnownBindingFlags), new Type[0])]
public static void TestWithBindingFlags ()
{
var constructor = typeof (KnownBindingFlags).GetConstructor (BindingFlags.Public, GetNullValue ("some argument", 2, 3), new Type[] { }, new ParameterModifier[] { });
@@ -158,7 +158,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[RecognizedReflectionAccessPattern (typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (BindingFlags), typeof (Binder), typeof (Type[]), typeof (ParameterModifier[]) },
- typeof (UnknownBindingFlags), ".ctor", new Type[0])]
+ typeof (UnknownBindingFlags), nameof (UnknownBindingFlags), new Type[0])]
public static void TestWithUnknownBindingFlags (BindingFlags bindingFlags)
{
// Since the binding flags are not known linker should mark all constructors on the type
@@ -189,7 +189,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[RecognizedReflectionAccessPattern (
typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (BindingFlags), typeof (Binder), typeof (CallingConventions), typeof (Type[]), typeof (ParameterModifier[]) },
- typeof (GetConstructor_BindingAttr_Binder_CallConvention_Types_Modifiers), ".ctor", new Type[0])]
+ typeof (GetConstructor_BindingAttr_Binder_CallConvention_Types_Modifiers), nameof (GetConstructor_BindingAttr_Binder_CallConvention_Types_Modifiers), new Type[0])]
public static void TestWithCallingConvention ()
{
var constructor = typeof (GetConstructor_BindingAttr_Binder_CallConvention_Types_Modifiers).GetConstructor (BindingFlags.Public, GetNullValue ("some argument", 2, 3), CallingConventions.HasThis, new Type[] { }, new ParameterModifier[] { });
@@ -238,7 +238,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[RecognizedReflectionAccessPattern (
typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (BindingFlags), typeof (Type[]) },
- typeof (GetConstructor_BindingAttr_Types), ".ctor", new Type[0])]
+ typeof (GetConstructor_BindingAttr_Types), nameof (GetConstructor_BindingAttr_Types), new Type[0])]
static void TestWithBindingFlagsAndTypes_EmptyTypes ()
{
var constructor = typeof (GetConstructor_BindingAttr_Types).GetConstructor (BindingFlags.Public, new Type[] { });
@@ -344,10 +344,10 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[RecognizedReflectionAccessPattern (
typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (BindingFlags), typeof (Binder), typeof (Type[]), typeof (ParameterModifier[]) },
- typeof (IfConstructor), ".ctor", new Type[0])]
+ typeof (IfConstructor), nameof (IfConstructor), new Type[0])]
[RecognizedReflectionAccessPattern (
typeof (Type), nameof (Type.GetConstructor), new Type[] { typeof (BindingFlags), typeof (Binder), typeof (Type[]), typeof (ParameterModifier[]) },
- typeof (ElseConstructor), ".ctor", new Type[0])]
+ typeof (ElseConstructor), nameof (ElseConstructor), new Type[0])]
public static void TestIfElse (bool decision)
{
Type myType;
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs
index b4b71d5eb..699bb9d9d 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs
@@ -245,7 +245,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[Kept]
- [ExpectedWarning ("IL2060", "Expression::Call")]
+ [ExpectedWarning ("IL2060", "Expression.Call")]
static void TestMethodWithRequirementsUnknownTypeArray (Type[] types)
{
// The passed in types array cannot be analyzed, so a warning is produced.
@@ -253,7 +253,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[Kept]
- [ExpectedWarning ("IL2060", "Expression::Call")]
+ [ExpectedWarning ("IL2060", "Expression.Call")]
static void TestMethodWithRequirementsButNoTypeArguments ()
{
Expression.Call (typeof (TestGenericMethods), nameof (GenericMethodWithRequirementsNoArguments), Type.EmptyTypes);
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs
index 39b6834a0..a137d122c 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs
@@ -27,9 +27,9 @@ namespace Mono.Linker.Tests.Cases.Reflection
#region RecognizedReflectionAccessPatterns
[RecognizedReflectionAccessPattern (
- typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) }, typeof (A), ".ctor", new Type[0])]
+ typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) }, typeof (A), "A", new Type[0])]
[RecognizedReflectionAccessPattern (
- typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) }, typeof (B), ".ctor", new Type[0])]
+ typeof (Expression), nameof (Expression.New), new Type[] { typeof (Type) }, typeof (B), "B", new Type[0])]
[Kept]
static void Branch_SystemTypeValueNode (int i)
{
diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs
index 88aa44e5f..ac6dab4e0 100644
--- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs
+++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs
@@ -924,13 +924,13 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
public static int field;
}
- [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess::field", "Message for --StaticCtorTriggeredByFieldAccess--", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", GlobalAnalysisOnly = true)]
static void TestStaticCtorMarkingIsTriggeredByFieldAccessWrite ()
{
StaticCtorTriggeredByFieldAccess.field = 1;
}
- [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess::field", "Message for --StaticCtorTriggeredByFieldAccess--", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "StaticCtorTriggeredByFieldAccess.field", "Message for --StaticCtorTriggeredByFieldAccess--", GlobalAnalysisOnly = true)]
static void TestStaticCtorMarkingTriggeredOnSecondAccessWrite ()
{
StaticCtorTriggeredByFieldAccess.field = 2;
@@ -954,7 +954,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
public static int field = 42;
}
- [ExpectedWarning ("IL2026", "StaticCCtorTriggeredByFieldAccessRead::field", "Message for --StaticCCtorTriggeredByFieldAccessRead--", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "StaticCCtorTriggeredByFieldAccessRead.field", "Message for --StaticCCtorTriggeredByFieldAccessRead--", GlobalAnalysisOnly = true)]
static void TestStaticCtorMarkingIsTriggeredByFieldAccessRead ()
{
var _ = StaticCCtorTriggeredByFieldAccessRead.field;
@@ -1104,7 +1104,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
[ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequiresUnreferencedCode.StaticMethod()", "--ClassWithRequiresUnreferencedCode--", GlobalAnalysisOnly = true)]
// Although we suppress the warning from RequiresOnMethod.MethodWithRUC () we still get a warning because we call CallRUCMethod() which is an static method on a type with RUC
[ExpectedWarning ("IL2026", "RequiresOnClass.ClassWithRequiresUnreferencedCode.CallRUCMethod()", "--ClassWithRequiresUnreferencedCode--", GlobalAnalysisOnly = true)]
- [ExpectedWarning ("IL2026", "ClassWithRequiresUnreferencedCode::Instance", "--ClassWithRequiresUnreferencedCode--", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "ClassWithRequiresUnreferencedCode.Instance", "--ClassWithRequiresUnreferencedCode--", GlobalAnalysisOnly = true)]
static void TestRequiresOnBaseButNotOnDerived ()
{
DerivedWithoutRequires.StaticMethodInInheritedClass ();
@@ -1180,7 +1180,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
public static event EventHandler Event;
}
- [ExpectedWarning ("IL2026", "MemberTypesWithRUC::field", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "MemberTypesWithRUC.field", GlobalAnalysisOnly = true)]
[ExpectedWarning ("IL2026", "MemberTypesWithRUC.Property.set", GlobalAnalysisOnly = true)]
[ExpectedWarning ("IL2026", "MemberTypesWithRUC.remove_Event", GlobalAnalysisOnly = true)]
static void TestOtherMemberTypesWithRUC ()
@@ -1338,9 +1338,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
public static int DerivedStaticField;
}
- [ExpectedWarning ("IL2026", "WithRUC::StaticField", GlobalAnalysisOnly = true)]
- [ExpectedWarning ("IL2026", "WithRUC::PrivateStaticField", GlobalAnalysisOnly = true)]
- [ExpectedWarning ("IL2026", "DerivedWithRUC::DerivedStaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "WithRUC.StaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "WithRUC.PrivateStaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "DerivedWithRUC.DerivedStaticField", GlobalAnalysisOnly = true)]
static void TestDAMAccess ()
{
typeof (WithRUC).RequiresPublicFields ();
@@ -1350,9 +1350,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
typeof (DerivedWithRUC).RequiresPublicFields ();
}
- [ExpectedWarning ("IL2026", "WithRUC::StaticField", GlobalAnalysisOnly = true)]
- [ExpectedWarning ("IL2026", "WithRUC::PrivateStaticField", GlobalAnalysisOnly = true)]
- [ExpectedWarning ("IL2026", "DerivedWithRUC::DerivedStaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "WithRUC.StaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "WithRUC.PrivateStaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "DerivedWithRUC.DerivedStaticField", GlobalAnalysisOnly = true)]
static void TestDirectReflectionAccess ()
{
typeof (WithRUC).GetField (nameof (WithRUC.StaticField));
@@ -1363,11 +1363,11 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
typeof (DerivedWithRUC).GetField (nameof (DerivedWithRUC.DerivedStaticField));
}
- [ExpectedWarning ("IL2026", "WithRUC::StaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "WithRUC.StaticField", GlobalAnalysisOnly = true)]
[DynamicDependency (nameof (WithRUC.StaticField), typeof (WithRUC))]
[DynamicDependency (nameof (WithRUC.InstanceField), typeof (WithRUC))] // Doesn't warn
[DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (DerivedWithoutRUC))] // Doesn't warn
- [ExpectedWarning ("IL2026", "DerivedWithRUC::DerivedStaticField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2026", "DerivedWithRUC.DerivedStaticField", GlobalAnalysisOnly = true)]
[DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (DerivedWithRUC))]
static void TestDynamicDependencyAccess ()
{
@@ -1381,13 +1381,13 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
[RequiresUnreferencedCode ("This class is dangerous")]
- [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass::baseField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseField", GlobalAnalysisOnly = true)]
class DAMAnnotatedClass : BaseForDAMAnnotatedClass
{
- [ExpectedWarning ("IL2112", "DAMAnnotatedClass::publicField", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicField", GlobalAnalysisOnly = true)]
public static int publicField;
- [ExpectedWarning ("IL2112", "DAMAnnotatedClass::privatefield", GlobalAnalysisOnly = true)]
+ [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privatefield", GlobalAnalysisOnly = true)]
static int privatefield;
}
diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs
index e36e039f5..c345b5a27 100644
--- a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs
+++ b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs
@@ -11,9 +11,9 @@ namespace Mono.Linker.Tests.Cases.Substitutions
[ExpectedWarning ("IL2010", "TestMethod_1", "stub", FileName = "SubstitutionsErrorCases.xml", SourceLine = 5, SourceColumn = 8)]
[ExpectedWarning ("IL2011", "TestMethod_2", "noaction", FileName = "SubstitutionsErrorCases.xml", SourceLine = 6, SourceColumn = 8)]
- [ExpectedWarning ("IL2013", "SubstitutionsErrorCases::InstanceField", FileName = "SubstitutionsErrorCases.xml", SourceLine = 8, SourceColumn = 8)]
- [ExpectedWarning ("IL2014", "SubstitutionsErrorCases::IntField", FileName = "SubstitutionsErrorCases.xml", SourceLine = 9, SourceColumn = 8)]
- [ExpectedWarning ("IL2015", "SubstitutionsErrorCases::IntField", "NonNumber", FileName = "SubstitutionsErrorCases.xml", SourceLine = 10, SourceColumn = 8)]
+ [ExpectedWarning ("IL2013", "SubstitutionsErrorCases.InstanceField", FileName = "SubstitutionsErrorCases.xml", SourceLine = 8, SourceColumn = 8)]
+ [ExpectedWarning ("IL2014", "SubstitutionsErrorCases.IntField", FileName = "SubstitutionsErrorCases.xml", SourceLine = 9, SourceColumn = 8)]
+ [ExpectedWarning ("IL2015", "SubstitutionsErrorCases.IntField", "NonNumber", FileName = "SubstitutionsErrorCases.xml", SourceLine = 10, SourceColumn = 8)]
[ExpectedWarning ("IL2007", "NonExistentAssembly", FileName = "SubstitutionsErrorCases.xml", SourceLine = 13, SourceColumn = 4)]
[ExpectedWarning ("IL2100", FileName = "SubstitutionsErrorCases.xml", SourceLine = 15, SourceColumn = 4)]
[ExpectedWarning ("IL2101", "library", "test", FileName = "ILLink.Substitutions.xml", SourceLine = 3, SourceColumn = 4)]
diff --git a/test/Mono.Linker.Tests/TestCases/Dependencies/SortedWarnings.txt b/test/Mono.Linker.Tests/TestCases/Dependencies/SortedWarnings.txt
index 5ece68f4b..2ef14654e 100644
--- a/test/Mono.Linker.Tests/TestCases/Dependencies/SortedWarnings.txt
+++ b/test/Mono.Linker.Tests/TestCases/Dependencies/SortedWarnings.txt
@@ -1,9 +1,9 @@
ILLink: Trim analysis warning IL2026: library: Using member 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.RUCType.RUCType()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. --RUCType--.
-ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.NestedType.Warning3(): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression::Call(System.Type,System.String,System.Type[],System.Linq.Expressions.Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
-ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.NestedType.Warning4<T>(List`1&): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression::Call(System.Type,System.String,System.Type[],System.Linq.Expressions.Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
-ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.Warning2.get: '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression::Call(System.Type,System.String,System.Type[],System.Linq.Expressions.Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
-ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.Main(): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression::Call(System.Type,System.String,System.Type[],System.Linq.Expressions.Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
-ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.Warning1(): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression::Call(System.Type,System.String,System.Type[],System.Linq.Expressions.Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
+ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.NestedType.Warning3(): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.Expression.Call(Type,String,Type[],Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
+ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.NestedType.Warning4<T>(List`1&): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.Expression.Call(Type,String,Type[],Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
+ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.Warning2.get: '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.Expression.Call(Type,String,Type[],Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
+ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.Main(): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.Expression.Call(Type,String,Type[],Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
+ILLink: Trim analysis warning IL2072: Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.Warning1(): '#0' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods', 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Linq.Expressions.Expression.Call(Type,String,Type[],Expression[])'. The return value of method 'Mono.Linker.Tests.Cases.Warnings.Dependencies.TriggerWarnings_Lib.TriggerUnrecognizedPattern()' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
ILLink: Trim analysis warning IL2075: Mono.Linker.Tests.Cases.Warnings.Individual.WarningsAreSorted.A.X(): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'. The return value of method 'System.Type.GetType(String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
ILLink: Trim analysis warning IL2075: Mono.Linker.Tests.Cases.Warnings.Individual.WarningsAreSorted.A.Y(): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'. The return value of method 'System.Type.GetType(String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
ILLink: Trim analysis warning IL2075: Mono.Linker.Tests.Cases.Warnings.Individual.WarningsAreSorted.B.X(): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'. The return value of method 'System.Type.GetType(String)' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs
index c717fbb5b..a4e418c6b 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs
@@ -200,9 +200,8 @@ namespace Mono.Linker.Tests.TestCasesRunner
protected virtual void AdditionalChecking (LinkedTestCaseResult linkResult, AssemblyDefinition original)
{
bool checkRemainingErrors = !HasAttribute (original.MainModule.GetType (linkResult.TestCase.ReconstructedFullTypeName), nameof (SkipRemainingErrorsValidationAttribute));
- VerifyLoggedMessages (original, linkResult.Logger, checkRemainingErrors);
+ VerifyLoggedMessages (original, linkResult.Logger, linkResult.Customizations.ReflectionPatternRecorder, checkRemainingErrors);
VerifyRecordedDependencies (original, linkResult.Customizations.DependencyRecorder);
- VerifyRecordedReflectionPatterns (original, linkResult.Customizations.ReflectionPatternRecorder);
}
protected virtual void InitialChecking (LinkedTestCaseResult linkResult, AssemblyDefinition original, AssemblyDefinition linked)
@@ -663,189 +662,366 @@ namespace Mono.Linker.Tests.TestCasesRunner
}
}
- IEnumerable<(ICustomAttributeProvider Provider, CustomAttribute Attribute)> GetAttributes (AssemblyDefinition assembly)
+ IEnumerable<ICustomAttributeProvider> GetAttributeProviders (AssemblyDefinition assembly)
{
foreach (var testType in assembly.AllDefinedTypes ()) {
- foreach (var provider in testType.AllMembers ().Append (testType)) {
- foreach (var attr in provider.CustomAttributes) {
- yield return (provider, attr);
- }
- }
- }
- foreach (var attr in assembly.CustomAttributes) {
- yield return (assembly, attr);
- }
- foreach (var module in assembly.Modules) {
- foreach (var attr in module.CustomAttributes)
- yield return (module, attr);
+ foreach (var provider in testType.AllMembers ())
+ yield return provider;
+
+ yield return testType;
}
+
+ foreach (var module in assembly.Modules)
+ yield return module;
+
+ yield return assembly;
}
- void VerifyLoggedMessages (AssemblyDefinition original, LinkerTestLogger logger, bool checkRemainingErrors)
+ void VerifyLoggedMessages (AssemblyDefinition original, LinkerTestLogger logger, TestReflectionPatternRecorder reflectionPatternRecorder, bool checkRemainingErrors)
{
List<MessageContainer> loggedMessages = logger.GetLoggedMessages ();
List<(IMemberDefinition, CustomAttribute)> expectedNoWarningsAttributes = new List<(IMemberDefinition, CustomAttribute)> ();
- foreach (var (attrProvider, attr) in GetAttributes (original)) {
- switch (attr.AttributeType.Name) {
-
- case nameof (LogContainsAttribute): {
- var expectedMessage = (string) attr.ConstructorArguments[0].Value;
-
- List<MessageContainer> matchedMessages;
- if ((bool) attr.ConstructorArguments[1].Value)
- matchedMessages = loggedMessages.Where (m => Regex.IsMatch (m.ToString (), expectedMessage)).ToList ();
- else
- matchedMessages = loggedMessages.Where (m => m.ToString ().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, loggedMessages)}");
-
- foreach (var matchedMessage in matchedMessages)
- loggedMessages.Remove (matchedMessage);
- }
- break;
+ foreach (var attrProvider in GetAttributeProviders (original)) {
+ bool foundReflectionAccessPatternAttributesToVerify = false;
+ foreach (var attr in attrProvider.CustomAttributes) {
+ switch (attr.AttributeType.Name) {
- case nameof (LogDoesNotContainAttribute): {
- var unexpectedMessage = (string) attr.ConstructorArguments[0].Value;
- foreach (var loggedMessage in loggedMessages) {
- Assert.That (() => {
- if ((bool) attr.ConstructorArguments[1].Value)
- return !Regex.IsMatch (loggedMessage.ToString (), unexpectedMessage);
- return !loggedMessage.ToString ().Contains (unexpectedMessage);
- },
- $"Expected to not find logged message matching `{unexpectedMessage}`, but found:{Environment.NewLine}{loggedMessage.ToString ()}{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, loggedMessages)}");
- }
- }
- break;
+ case nameof (LogContainsAttribute): {
+ var expectedMessage = (string) attr.ConstructorArguments[0].Value;
- case nameof (ExpectedWarningAttribute): {
- var expectedWarningCode = (string) attr.GetConstructorArgumentValue (0);
- if (!expectedWarningCode.StartsWith ("IL")) {
- Assert.Fail ($"The warning code specified in {nameof (ExpectedWarningAttribute)} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'.");
- }
- 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");
- bool? isCompilerGeneratedCode = (bool?) attr.GetPropertyValue ("CompilerGeneratedCode");
+ List<MessageContainer> matchedMessages;
+ if ((bool) attr.ConstructorArguments[1].Value)
+ matchedMessages = loggedMessages.Where (m => Regex.IsMatch (m.ToString (), expectedMessage)).ToList ();
+ else
+ matchedMessages = loggedMessages.Where (m => m.ToString ().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, loggedMessages)}");
- int expectedWarningCodeNumber = int.Parse (expectedWarningCode.Substring (2));
- string expectedOrigin = null;
+ foreach (var matchedMessage in matchedMessages)
+ loggedMessages.Remove (matchedMessage);
+ }
+ break;
+
+ case nameof (LogDoesNotContainAttribute): {
+ var unexpectedMessage = (string) attr.ConstructorArguments[0].Value;
+ foreach (var loggedMessage in loggedMessages) {
+ Assert.That (() => {
+ if ((bool) attr.ConstructorArguments[1].Value)
+ return !Regex.IsMatch (loggedMessage.ToString (), unexpectedMessage);
+ return !loggedMessage.ToString ().Contains (unexpectedMessage);
+ },
+ $"Expected to not find logged message matching `{unexpectedMessage}`, but found:{Environment.NewLine}{loggedMessage.ToString ()}{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, loggedMessages)}");
+ }
+ }
+ break;
- var matchedMessages = loggedMessages.Where (mc => {
- if (mc.Category != MessageCategory.Warning || mc.Code != expectedWarningCodeNumber)
- return false;
+ case nameof (ExpectedWarningAttribute): {
+ var expectedWarningCode = (string) attr.GetConstructorArgumentValue (0);
+ if (!expectedWarningCode.StartsWith ("IL")) {
+ Assert.Fail ($"The warning code specified in {nameof (ExpectedWarningAttribute)} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'.");
+ }
+ 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");
+ bool? isCompilerGeneratedCode = (bool?) attr.GetPropertyValue ("CompilerGeneratedCode");
- foreach (var expectedMessage in expectedMessageContains)
- if (!mc.Text.Contains (expectedMessage))
- return false;
+ int expectedWarningCodeNumber = int.Parse (expectedWarningCode.Substring (2));
+ string expectedOrigin = null;
- if (fileName != null) {
- if (mc.Origin == null)
+ var matchedMessages = loggedMessages.Where (mc => {
+ if (mc.Category != MessageCategory.Warning || mc.Code != expectedWarningCodeNumber)
return false;
- var actualOrigin = mc.Origin.Value;
- if (actualOrigin.FileName != null) {
- // Note: string.Compare(string, StringComparison) doesn't exist in .NET Framework API set
- if (actualOrigin.FileName.IndexOf (fileName, StringComparison.OrdinalIgnoreCase) < 0)
+ foreach (var expectedMessage in expectedMessageContains)
+ if (!mc.Text.Contains (expectedMessage))
return false;
- if (sourceLine != null && mc.Origin?.SourceLine != sourceLine.Value)
+ if (fileName != null) {
+ if (mc.Origin == null)
return false;
- if (sourceColumn != null && mc.Origin?.SourceColumn != sourceColumn.Value)
- return false;
- } else {
- // The warning was logged with member/ILoffset, so it didn't have line/column info filled
- // but it will be computed from PDBs, so instead compare it in a string representation
- if (expectedOrigin == null) {
- expectedOrigin = fileName;
- if (sourceLine.HasValue) {
- expectedOrigin += "(" + sourceLine.Value;
- if (sourceColumn.HasValue)
- expectedOrigin += "," + sourceColumn.Value;
- expectedOrigin += ")";
+ var actualOrigin = mc.Origin.Value;
+ if (actualOrigin.FileName != null) {
+ // Note: string.Compare(string, StringComparison) doesn't exist in .NET Framework API set
+ if (actualOrigin.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 {
+ // The warning was logged with member/ILoffset, so it didn't have line/column info filled
+ // but it will be computed from PDBs, so instead compare it in a string representation
+ if (expectedOrigin == null) {
+ expectedOrigin = fileName;
+ if (sourceLine.HasValue) {
+ expectedOrigin += "(" + sourceLine.Value;
+ if (sourceColumn.HasValue)
+ expectedOrigin += "," + sourceColumn.Value;
+ expectedOrigin += ")";
+ }
}
+
+ if (!actualOrigin.ToString ().EndsWith (expectedOrigin, StringComparison.OrdinalIgnoreCase))
+ return false;
+ }
+ } else if (isCompilerGeneratedCode == true) {
+ MethodDefinition methodDefinition = mc.Origin?.Provider as MethodDefinition;
+ if (methodDefinition != null) {
+ if (attrProvider is not IMemberDefinition expectedMember)
+ return false;
+
+ string actualName = methodDefinition.DeclaringType.FullName + "." + methodDefinition.Name;
+
+ if (actualName.StartsWith (expectedMember.DeclaringType.FullName) &&
+ actualName.Contains ("<" + expectedMember.Name + ">"))
+ return true;
+ if (methodDefinition.Name == ".ctor" &&
+ methodDefinition.DeclaringType.FullName == expectedMember.FullName)
+ return true;
}
- if (!actualOrigin.ToString ().EndsWith (expectedOrigin, StringComparison.OrdinalIgnoreCase))
- return false;
+ return false;
+ } else {
+ return LogMessageHasSameOriginMember (mc, attrProvider);
}
- } else if (isCompilerGeneratedCode == true) {
- MethodDefinition methodDefinition = mc.Origin?.Provider as MethodDefinition;
- if (methodDefinition != null) {
- if (attrProvider is not IMemberDefinition expectedMember)
- return false;
- string actualName = methodDefinition.DeclaringType.FullName + "." + methodDefinition.Name;
+ return true;
+ }).ToList ();
+
+ var expectedOriginString = fileName == null
+ ? attrProvider switch {
+ MethodDefinition method => method.GetDisplayName (),
+ IMemberDefinition member => member.FullName,
+ AssemblyDefinition asm => asm.Name.Name,
+ _ => throw new NotImplementedException ()
+ } + ": "
+ : "";
+
+ Assert.IsTrue (
+ matchedMessages.Count > 0,
+ $"Expected to find warning: {(fileName != null ? fileName + (sourceLine != null ? $"({sourceLine},{sourceColumn})" : "") + ": " : "")}" +
+ $"warning {expectedWarningCode}: {expectedOriginString}" +
+ $"and message containing {string.Join (" ", expectedMessageContains.Select (m => "'" + m + "'"))}, " +
+ $"but no such message was found.{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, loggedMessages)}");
+
+ foreach (var matchedMessage in matchedMessages)
+ loggedMessages.Remove (matchedMessage);
+ }
+ break;
+
+ case nameof (RecognizedReflectionAccessPatternAttribute): {
+ foundReflectionAccessPatternAttributesToVerify = true;
+
+ // Special case for default .ctor - just trigger the overall verification on the method
+ // but don't verify any specific pattern.
+ if (attr.ConstructorArguments.Count == 0)
+ continue;
- if (actualName.StartsWith (expectedMember.DeclaringType.FullName) &&
- actualName.Contains ("<" + expectedMember.Name + ">"))
- return true;
- if (methodDefinition.Name == ".ctor" &&
- methodDefinition.DeclaringType.FullName == expectedMember.FullName)
- return true;
+ string expectedSourceMember = GetFullMemberNameFromDefinition (attrProvider);
+ string expectedReflectionMember = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 0, out string expectedReflectionMemberGenericMember);
+ string expectedAccessedItem = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 3, out string _genericMember);
+
+ var matchedPatterns = reflectionPatternRecorder.RecognizedPatterns.Where (pattern => {
+ if (GetFullMemberNameFromDefinition (pattern.Source) != expectedSourceMember)
+ return false;
+
+ string actualAccessOperation = null;
+ if (pattern.SourceInstruction?.Operand is IMetadataTokenProvider sourceOperand)
+ actualAccessOperation = GetFullMemberNameFromDefinition (sourceOperand);
+
+ if (actualAccessOperation != expectedReflectionMember)
+ return false;
+
+ if (GetFullMemberNameFromDefinition (pattern.AccessedItem) != expectedAccessedItem)
+ return false;
+
+ return true;
+ });
+
+ if (!matchedPatterns.Any ()) {
+ string sourceMemberCandidates = string.Join (Environment.NewLine, reflectionPatternRecorder.RecognizedPatterns
+ .Where (p => GetFullMemberNameFromDefinition (p.Source)?.ToLowerInvariant ()?.Contains (expectedReflectionMember.ToLowerInvariant ()) == true)
+ .Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)));
+ string reflectionMemberCandidates = string.Join (Environment.NewLine, reflectionPatternRecorder.RecognizedPatterns
+ .Where (p => GetFullMemberNameFromDefinition (p.SourceInstruction?.Operand as IMetadataTokenProvider)?.ToLowerInvariant ()?.Contains (expectedReflectionMember.ToLowerInvariant ()) == true)
+ .Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)));
+
+ Assert.Fail (
+ $"Expected to find recognized reflection access pattern '{expectedSourceMember}: Usage of {expectedReflectionMember} accessed {expectedAccessedItem}'{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.");
+ }
+
+ reflectionPatternRecorder.RecognizedPatterns.Remove (matchedPatterns.First ());
+ }
+ break;
+
+ case nameof (UnrecognizedReflectionAccessPatternAttribute): {
+ Debug.Assert (attr.ConstructorArguments[0].Type.MetadataType != MetadataType.String);
+
+ foundReflectionAccessPatternAttributesToVerify = true;
+
+ string expectedSourceMember = GetFullMemberNameFromDefinition (attrProvider);
+ string expectedReflectionMember = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 0, out string expectedReflectionMemberGenericMember);
+ string expectedReflectionMemberWithoutReturnType = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 0, out string _genericType, includeReturnType: false);
+ 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"))
+ Assert.Fail ($"The warning code specified in {nameof (UnrecognizedReflectionAccessPatternAttribute)} must start with the 'IL' prefix. Specified value: '{codeString}'");
+ expectedMessageCode = int.Parse (codeString.Substring (2));
}
+ }
- return false;
- } else {
- return LogMessageHasSameOriginMember (mc, attrProvider);
+ // Validate expected unrecognized patterns by looking for them in both the logged messages and the recorded unrecognized patterns.
+ // Checking for both here ensures that the unrecognized pattern attributes use the same signature formats as the logged warnings.
+ // The Roslyn analyzer will treat these attributes similarly, checking them against logged diagnostics only.
+ // Eventually this should go away as we replace UnrecognizedReflectionAccessPatternAttribute with ExpectedWarningAttribute.
+
+ var matchedMessages = loggedMessages.Where (mc => {
+ if (mc.Category != MessageCategory.Warning)
+ return false;
+
+ if (!LogMessageHasSameOriginMember (mc, attrProvider))
+ return false;
+
+ if (!mc.Text.Contains (expectedReflectionMemberWithoutReturnType))
+ return false;
+
+ if (expectedReflectionMemberGenericMember != null && !mc.Text.Contains (expectedReflectionMemberGenericMember))
+ return false;
+
+ // Note: string.Compare(string, StringComparison) doesn't exist in .NET Framework API set
+ if (expectedMessageParts != null && expectedMessageParts.Any (p => mc.Text.IndexOf (p, StringComparison.Ordinal) < 0))
+ return false;
+
+ if (expectedMessageCode.HasValue && mc.Code != expectedMessageCode.Value)
+ return false;
+
+ return true;
+ }).ToList ();
+
+ var matchedPatterns = reflectionPatternRecorder.UnrecognizedPatterns.Where (pattern => {
+ if (GetFullMemberNameFromDefinition (pattern.Source) != expectedSourceMember)
+ return false;
+
+ string actualAccessOperation = null;
+ string actualAccessGenericMember = null;
+ if (pattern.SourceInstruction?.Operand is IMetadataTokenProvider sourceOperand)
+ actualAccessOperation = GetFullMemberNameFromDefinition (sourceOperand);
+ else
+ actualAccessOperation = GetFullMemberNameFromDefinition (pattern.AccessedItem, out actualAccessGenericMember);
+
+ if (actualAccessOperation != expectedReflectionMember)
+ return false;
+
+ if (actualAccessGenericMember != expectedReflectionMemberGenericMember)
+ return false;
+
+ if (expectedMessageParts != null && expectedMessageParts.Any (p => pattern.Message.IndexOf (p, StringComparison.Ordinal) < 0))
+ return false;
+
+ if (expectedMessageCode.HasValue && pattern.MessageCode != expectedMessageCode.Value)
+ return false;
+
+ return true;
+ }).ToList ();
+
+ if (matchedMessages.Any ())
+ loggedMessages.Remove (matchedMessages.First ());
+
+ if (matchedPatterns.Any ())
+ reflectionPatternRecorder.UnrecognizedPatterns.Remove (matchedPatterns.First ());
+
+ string expectedUnrecognizedPatternMessage =
+ $"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 + "'")))}";
+
+ Assert.AreEqual (matchedMessages.Count (), matchedPatterns.Count (),
+ $"Inconsistency between logged messages and recorded patterns.{Environment.NewLine}{expectedUnrecognizedPatternMessage}{Environment.NewLine}" +
+ $"Matched messages: {Environment.NewLine}{string.Join (Environment.NewLine, matchedMessages.Select (mc => "\t" + mc.Text))}{Environment.NewLine}" +
+ $"Matched unrecognized patterns: {Environment.NewLine}{string.Join (Environment.NewLine, matchedPatterns.Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)))}{Environment.NewLine}");
+
+ if (!matchedMessages.Any ()) {
+ string sourceMemberCandidates = string.Join (Environment.NewLine, loggedMessages
+ .Where (mc => mc.Text.Contains (expectedSourceMember.ToLowerInvariant ()))
+ .Select (mc => "\t" + mc.Text));
+ string reflectionMemberCandidates = string.Join (Environment.NewLine, loggedMessages
+ .Where (mc => mc.Text.Contains (expectedReflectionMember.ToLowerInvariant ()))
+ .Select (mc => "\t" + mc.Text));
+
+ Assert.Fail (
+ $"{expectedUnrecognizedPatternMessage}{Environment.NewLine}" +
+ $"Potential messages matching the source member: {Environment.NewLine}{sourceMemberCandidates}{Environment.NewLine}" +
+ $"Potential messages 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.");
}
+ }
+ break;
+
+ case nameof (ExpectedNoWarningsAttribute):
+ // Postpone processing of negative checks, to make it possible to mark some warnings as expected (will be removed from the list above)
+ // and then do the negative check on the rest.
+ var memberDefinition = attrProvider as IMemberDefinition;
+ Assert.NotNull (memberDefinition);
+ expectedNoWarningsAttributes.Add ((memberDefinition, attr));
+ break;
+ }
+ }
+
+ // Validate that there are no other reported unrecognized patterns on the member
+ if (foundReflectionAccessPatternAttributesToVerify) {
+ string expectedSourceMember = GetFullMemberNameFromDefinition (attrProvider);
+ var unrecognizedPatternsForSourceMember = reflectionPatternRecorder.UnrecognizedPatterns.Where (pattern => {
+ if (GetFullMemberNameFromDefinition (pattern.Source) != expectedSourceMember)
+ return false;
- return true;
- }).ToList ();
-
- var expectedOriginString = fileName == null
- ? attrProvider switch {
- MethodDefinition method => method.GetDisplayName (),
- IMemberDefinition member => member.FullName,
- AssemblyDefinition asm => asm.Name.Name,
- _ => throw new NotImplementedException ()
- } + ": "
- : "";
-
- Assert.IsTrue (
- matchedMessages.Count > 0,
- $"Expected to find warning: {(fileName != null ? fileName + (sourceLine != null ? $"({sourceLine},{sourceColumn})" : "") + ": " : "")}" +
- $"warning {expectedWarningCode}: {expectedOriginString}" +
- $"and message containing {string.Join (" ", expectedMessageContains.Select (m => "'" + m + "'"))}, " +
- $"but no such message was found.{Environment.NewLine}Logged messages:{Environment.NewLine}{string.Join (Environment.NewLine, loggedMessages)}");
-
- foreach (var matchedMessage in matchedMessages)
- loggedMessages.Remove (matchedMessage);
+ return true;
+ });
+
+ if (unrecognizedPatternsForSourceMember.Any ()) {
+ string unrecognizedPatterns = string.Join (Environment.NewLine, unrecognizedPatternsForSourceMember
+ .Select (p => "\t" + UnrecognizedReflectionAccessPatternToString (p)));
+
+ Assert.Fail (
+ $"Member {expectedSourceMember} has either {nameof (RecognizedReflectionAccessPatternAttribute)} or {nameof (UnrecognizedReflectionAccessPatternAttribute)} attributes.{Environment.NewLine}" +
+ $"Some reported unrecognized patterns are not expected by the test (there's no matching attribute for them):{Environment.NewLine}" +
+ $"{unrecognizedPatterns}");
}
- break;
+ }
+ }
- // These are validated in VerifyRecordedReflectionPatterns as well, but we need to remove any warnings these might refer to from the list
- // so that we can correctly validate presense of warnings
- case nameof (UnrecognizedReflectionAccessPatternAttribute): {
- string expectedWarningCode = null;
- if (attr.ConstructorArguments.Count >= 5) {
- expectedWarningCode = (string) attr.ConstructorArguments[4].Value;
- if (expectedWarningCode != null && !expectedWarningCode.StartsWith ("IL"))
- Assert.Fail ($"The warning code specified in {nameof (UnrecognizedReflectionAccessPatternAttribute)} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'");
- }
+ foreach (var typeToVerify in original.MainModule.AllDefinedTypes ()) {
+ foreach (var attr in typeToVerify.CustomAttributes) {
+ if (attr.AttributeType.Resolve ()?.Name == nameof (VerifyAllReflectionAccessPatternsAreValidatedAttribute)) {
+ // By now all verified recorded patterns were removed from the test recorder lists, so validate
+ // that there are no remaining patterns for this type.
+ var recognizedPatternsForType = reflectionPatternRecorder.RecognizedPatterns
+ .Where (pattern => (pattern.Source is IMemberDefinition member) && member.DeclaringType?.FullName == typeToVerify.FullName);
+ var unrecognizedPatternsForType = reflectionPatternRecorder.UnrecognizedPatterns
+ .Where (pattern => (pattern.Source is IMemberDefinition member) && member.DeclaringType?.FullName == typeToVerify.FullName);
- if (expectedWarningCode != null) {
- int expectedWarningCodeNumber = int.Parse (expectedWarningCode.Substring (2));
+ if (recognizedPatternsForType.Any () || unrecognizedPatternsForType.Any ()) {
+ string recognizedPatterns = string.Join (Environment.NewLine, recognizedPatternsForType
+ .Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)));
+ string unrecognizedPatterns = string.Join (Environment.NewLine, unrecognizedPatternsForType
+ .Select (p => "\t" + UnrecognizedReflectionAccessPatternToString (p)));
- var matchedMessages = loggedMessages.Where (mc =>
- mc.Category == MessageCategory.Warning &&
- mc.Code == expectedWarningCodeNumber &&
- LogMessageHasSameOriginMember (mc, attrProvider)).ToList ();
- foreach (var matchedMessage in matchedMessages)
- loggedMessages.Remove (matchedMessage);
+ Assert.Fail (
+ $"All reflection patterns should be verified by test attributes for type {typeToVerify.FullName}, but some were not: {Environment.NewLine}" +
+ $"Recognized patterns which were not verified: {Environment.NewLine}{recognizedPatterns}{Environment.NewLine}" +
+ $"Unrecognized patterns which were not verified: {Environment.NewLine}{unrecognizedPatterns}{Environment.NewLine}");
}
}
- break;
-
- case nameof (ExpectedNoWarningsAttribute):
- // Postpone processing of negative checks, to make it possible to mark some warnings as expected (will be removed from the list above)
- // and then do the negative check on the rest.
- var memberDefinition = attrProvider as IMemberDefinition;
- Assert.NotNull (memberDefinition);
- expectedNoWarningsAttributes.Add ((memberDefinition, attr));
- break;
}
}
@@ -953,158 +1129,6 @@ namespace Mono.Linker.Tests.TestCasesRunner
}
}
- void VerifyRecordedReflectionPatterns (AssemblyDefinition original, TestReflectionPatternRecorder reflectionPatternRecorder)
- {
- foreach (var expectedSourceMemberDefinition in original.MainModule.AllDefinedTypes ().SelectMany (t => t.AllMembers ().Append (t)).Distinct ()) {
- bool foundAttributesToVerify = false;
- foreach (var attr in expectedSourceMemberDefinition.CustomAttributes) {
- if (attr.AttributeType.Resolve ()?.Name == nameof (RecognizedReflectionAccessPatternAttribute)) {
- foundAttributesToVerify = true;
-
- // Special case for default .ctor - just trigger the overall verification on the method
- // but don't verify any specific pattern.
- if (attr.ConstructorArguments.Count == 0)
- continue;
-
- string expectedSourceMember = GetFullMemberNameFromDefinition (expectedSourceMemberDefinition);
- string expectedReflectionMember = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 0);
- string expectedAccessedItem = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 3);
-
- if (!reflectionPatternRecorder.RecognizedPatterns.Any (pattern => {
- if (GetFullMemberNameFromDefinition (pattern.Source) != expectedSourceMember)
- return false;
-
- string actualAccessOperation = null;
- if (pattern.SourceInstruction?.Operand is IMetadataTokenProvider sourceOperand)
- actualAccessOperation = GetFullMemberNameFromDefinition (sourceOperand);
-
- if (actualAccessOperation != expectedReflectionMember)
- return false;
-
- if (GetFullMemberNameFromDefinition (pattern.AccessedItem) != expectedAccessedItem)
- return false;
-
- reflectionPatternRecorder.RecognizedPatterns.Remove (pattern);
- return true;
- })) {
- string sourceMemberCandidates = string.Join (Environment.NewLine, reflectionPatternRecorder.RecognizedPatterns
- .Where (p => GetFullMemberNameFromDefinition (p.Source)?.ToLowerInvariant ()?.Contains (expectedReflectionMember.ToLowerInvariant ()) == true)
- .Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)));
- string reflectionMemberCandidates = string.Join (Environment.NewLine, reflectionPatternRecorder.RecognizedPatterns
- .Where (p => GetFullMemberNameFromDefinition (p.SourceInstruction?.Operand as IMetadataTokenProvider)?.ToLowerInvariant ()?.Contains (expectedReflectionMember.ToLowerInvariant ()) == true)
- .Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)));
-
- Assert.Fail (
- $"Expected to find recognized reflection access pattern '{expectedSourceMember}: Usage of {expectedReflectionMember} accessed {expectedAccessedItem}'{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.");
- }
- } else if (attr.AttributeType.Resolve ()?.Name == nameof (UnrecognizedReflectionAccessPatternAttribute) &&
- attr.ConstructorArguments[0].Type.MetadataType != MetadataType.String) {
- foundAttributesToVerify = true;
- string expectedSourceMember = GetFullMemberNameFromDefinition (expectedSourceMemberDefinition);
- string expectedReflectionMember = GetFullMemberNameFromReflectionAccessPatternAttribute (attr, constructorArgumentsOffset: 0);
- 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"))
- Assert.Fail ($"The warning code specified in {nameof (UnrecognizedReflectionAccessPatternAttribute)} must start with the 'IL' prefix. Specified value: '{codeString}'");
- expectedMessageCode = int.Parse (codeString.Substring (2));
- }
- }
-
- if (!reflectionPatternRecorder.UnrecognizedPatterns.Any (pattern => {
- if (GetFullMemberNameFromDefinition (pattern.Source) != expectedSourceMember)
- return false;
-
- string actualAccessOperation = null;
- if (pattern.SourceInstruction?.Operand is IMetadataTokenProvider sourceOperand)
- actualAccessOperation = GetFullMemberNameFromDefinition (sourceOperand);
- else
- actualAccessOperation = GetFullMemberNameFromDefinition (pattern.AccessedItem);
-
- if (actualAccessOperation != expectedReflectionMember)
- return false;
-
- // 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);
- return true;
- })) {
- string sourceMemberCandidates = string.Join (Environment.NewLine, reflectionPatternRecorder.UnrecognizedPatterns
- .Where (p => GetFullMemberNameFromDefinition (p.Source)?.ToLowerInvariant ()?.Contains (expectedSourceMember.ToLowerInvariant ()) == true)
- .Select (p => "\t" + UnrecognizedReflectionAccessPatternToString (p)));
- string reflectionMemberCandidates = string.Join (Environment.NewLine, reflectionPatternRecorder.UnrecognizedPatterns
- .Where (p => GetFullMemberNameFromDefinition (p.SourceInstruction != null ? p.SourceInstruction.Operand as IMetadataTokenProvider : p.AccessedItem)?.ToLowerInvariant ()?.Contains (expectedReflectionMember.ToLowerInvariant ()) == true)
- .Select (p => "\t" + UnrecognizedReflectionAccessPatternToString (p)));
-
- Assert.Fail (
- $"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.");
- }
- }
- }
-
- if (foundAttributesToVerify) {
- // Validate that there are no other reported unrecognized patterns on the member
- string expectedSourceMember = GetFullMemberNameFromDefinition (expectedSourceMemberDefinition);
- var unrecognizedPatternsForSourceMember = reflectionPatternRecorder.UnrecognizedPatterns.Where (pattern => {
- if (GetFullMemberNameFromDefinition (pattern.Source) != expectedSourceMember)
- return false;
-
- return true;
- });
-
- if (unrecognizedPatternsForSourceMember.Any ()) {
- string unrecognizedPatterns = string.Join (Environment.NewLine, unrecognizedPatternsForSourceMember
- .Select (p => "\t" + UnrecognizedReflectionAccessPatternToString (p)));
-
- Assert.Fail (
- $"Member {expectedSourceMember} has either {nameof (RecognizedReflectionAccessPatternAttribute)} or {nameof (UnrecognizedReflectionAccessPatternAttribute)} attributes.{Environment.NewLine}" +
- $"Some reported unrecognized patterns are not expected by the test (there's no matching attribute for them):{Environment.NewLine}" +
- $"{unrecognizedPatterns}");
- }
- }
- }
-
- foreach (var typeToVerify in original.MainModule.AllDefinedTypes ()) {
- foreach (var attr in typeToVerify.CustomAttributes) {
- if (attr.AttributeType.Resolve ()?.Name == nameof (VerifyAllReflectionAccessPatternsAreValidatedAttribute)) {
- // By now all verified recorded patterns were removed from the test recorder lists, so validate
- // that there are no remaining patterns for this type.
- var recognizedPatternsForType = reflectionPatternRecorder.RecognizedPatterns
- .Where (pattern => (pattern.Source is IMemberDefinition member) && member.DeclaringType?.FullName == typeToVerify.FullName);
- var unrecognizedPatternsForType = reflectionPatternRecorder.UnrecognizedPatterns
- .Where (pattern => (pattern.Source is IMemberDefinition member) && member.DeclaringType?.FullName == typeToVerify.FullName);
-
- if (recognizedPatternsForType.Any () || unrecognizedPatternsForType.Any ()) {
- string recognizedPatterns = string.Join (Environment.NewLine, recognizedPatternsForType
- .Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)));
- string unrecognizedPatterns = string.Join (Environment.NewLine, unrecognizedPatternsForType
- .Select (p => "\t" + UnrecognizedReflectionAccessPatternToString (p)));
-
- Assert.Fail (
- $"All reflection patterns should be verified by test attributes for type {typeToVerify.FullName}, but some were not: {Environment.NewLine}" +
- $"Recognized patterns which were not verified: {Environment.NewLine}{recognizedPatterns}{Environment.NewLine}" +
- $"Unrecognized patterns which were not verified: {Environment.NewLine}{unrecognizedPatterns}{Environment.NewLine}");
- }
- }
- }
- }
- }
-
void VerifyExpectedInstructionSequenceOnMemberInAssembly (CustomAttribute inAssemblyAttribute, TypeDefinition linkedType)
{
var originalType = GetOriginalTypeFromInAssemblyAttribute (inAssemblyAttribute);
@@ -1127,29 +1151,58 @@ namespace Mono.Linker.Tests.TestCasesRunner
Assert.Fail ($"Invalid test assertion. No method named `{memberName}` exists on the original type `{originalType}`");
}
- static string GetFullMemberNameFromReflectionAccessPatternAttribute (CustomAttribute attr, int constructorArgumentsOffset)
+ static string GetFullMemberNameFromReflectionAccessPatternAttribute (CustomAttribute attr, int constructorArgumentsOffset, out string genericMember, bool includeReturnType = true)
{
- var type = attr.ConstructorArguments[constructorArgumentsOffset].Value;
+ genericMember = null;
+ var type = (attr.ConstructorArguments[constructorArgumentsOffset].Value as TypeReference).Resolve ();
+ Debug.Assert (type != null);
var memberName = (string) attr.ConstructorArguments[constructorArgumentsOffset + 1].Value;
var parameterTypes = (CustomAttributeArgument[]) attr.ConstructorArguments[constructorArgumentsOffset + 2].Value;
- string fullName = type.ToString ();
- if (attr.AttributeType.Name == "UnrecognizedReflectionAccessPatternAttribute") {
- var returnType = attr.ConstructorArguments[constructorArgumentsOffset + 5].Value;
- if (returnType != null) {
- fullName = fullName.Insert (0, returnType.ToString () + " ");
+ string genericParameter = null;
+
+ static string GetFullName (TypeDefinition type, string memberName, CustomAttributeArgument[] parameterTypes)
+ {
+ string fullName = type.GetDisplayName ();
+
+ if (memberName == null)
+ return fullName;
+
+ fullName += "." + memberName;
+ if (memberName.EndsWith (".get") || memberName.EndsWith (".set"))
+ return fullName;
+
+ if (parameterTypes != null) {
+ fullName += "(";
+ fullName += string.Join (",", parameterTypes.Select (pt => pt.Value switch {
+ TypeReference typeRef => typeRef.GetDisplayNameWithoutNamespace ().ToString (),
+ string str => str,
+ _ => throw new NotImplementedException ()
+ }));
+ fullName += ")";
}
- }
- if (memberName == null) {
return fullName;
}
- fullName += "::" + memberName;
- if (memberName.EndsWith (".get") || memberName.EndsWith (".set"))
- return fullName;
- if (parameterTypes != null) {
- fullName += "(" + string.Join (",", parameterTypes.Select (t => t.Value.ToString ())) + ")";
+ var fullName = GetFullName (type, memberName, parameterTypes);
+
+ if (attr.AttributeType.Name == "UnrecognizedReflectionAccessPatternAttribute") {
+ if (includeReturnType) {
+ var returnType = attr.ConstructorArguments[constructorArgumentsOffset + 5].Value;
+ if (returnType != null)
+ fullName = fullName.Insert (0, returnType.ToString () + " ");
+ }
+
+ genericParameter = attr.ConstructorArguments[constructorArgumentsOffset + 6].Value as string;
+ }
+
+ if (genericParameter != null) {
+ Debug.Assert (memberName == null || parameterTypes != null,
+ "Generic parameter should only be specified for types (with null memberName), or methods (with non-null parameterTypes).");
+
+ genericMember = fullName;
+ return genericParameter;
}
return fullName;
@@ -1171,12 +1224,19 @@ namespace Mono.Linker.Tests.TestCasesRunner
static string GetFullMemberNameFromDefinition (IMetadataTokenProvider member)
{
- // Method which basically returns the same as member.ToString() but without the return type
- // of a method (if it's a method).
- // We need this as the GetFullMemberNameFromReflectionAccessPatternAttribute can't guess the return type
- // as it would have to actually resolve the referenced method, which is very expensive and unnecessary
- // for the tests to work (the return types are redundant piece of information anyway).
+ return GetFullMemberNameFromDefinition (member, out string genericMember);
+ }
+
+ static string GetFullMemberNameFromDefinition (IMetadataTokenProvider member, out string genericMember)
+ {
+ // Method which basically returns the same as member.GetDisplayName () for the resolved member,
+ // but with the return type if the input is a MethodReturnType.
+ // If the input is a generic parameter, the returned string will be the name of the generic
+ // parameter, and the full member name of the member which declares the generic parameter will be
+ // returned via the out parameter.
+
+ genericMember = null;
if (member == null)
return null;
else if (member is TypeSpecification typeSpecification)
@@ -1186,47 +1246,31 @@ namespace Mono.Linker.Tests.TestCasesRunner
else if (member is GenericParameter genericParameter) {
var declaringType = genericParameter.DeclaringType?.Resolve ();
if (declaringType != null) {
- return declaringType.FullName + "::" + genericParameter.FullName;
+ genericMember = declaringType.GetDisplayName ();
+ return genericParameter.FullName;
}
var declaringMethod = genericParameter.DeclaringMethod?.Resolve ();
if (declaringMethod != null) {
- return GetFullMemberNameFromDefinition (declaringMethod) + "::" + genericParameter.FullName;
+ genericMember = GetFullMemberNameFromDefinition (declaringMethod);
+ return genericParameter.FullName;
}
return genericParameter.FullName;
} else if (member is MemberReference memberReference)
member = memberReference.Resolve ();
- if (member is IMemberDefinition memberDefinition) {
- if (memberDefinition is TypeDefinition) {
- return memberDefinition.FullName;
- }
-
- string fullName = memberDefinition.DeclaringType.FullName + "::";
- if (memberDefinition is MethodDefinition method) {
- if (method.IsSetter || method.IsGetter)
- fullName += method.IsSetter ? method.Name.Substring (4) + ".set" : method.Name.Substring (4) + ".get";
- else
- fullName += method.GetSignature ();
- } else {
- fullName += memberDefinition.Name;
- }
+ if (member is MemberReference memberRef)
+ return memberRef.GetDisplayName ();
- return fullName;
- } else if (member is ParameterDefinition param) {
- string type = param.ParameterType.FullName;
- return $"{type}::{param.Name}";
- } else if (member is MethodReturnType returnType) {
+ if (member is MethodReturnType returnType) {
MethodDefinition method = (MethodDefinition) returnType.Method;
- string fullName = method.ReturnType + " " + method.DeclaringType.FullName + "::";
- if (method.IsSetter || method.IsGetter)
- fullName += method.IsSetter ? method.Name.Substring (4) + ".set" : method.Name.Substring (4) + ".get";
- else
- fullName += method.GetSignature ();
- return fullName;
+ return method.ReturnType + " " + method.GetDisplayName ();
}
+ if (member is AssemblyDefinition assembly)
+ return assembly.Name.Name;
+
throw new NotImplementedException ($"Getting the full member name has not been implemented for {member}");
}