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:
authorIsabel Serrato <56236284+iserrato@users.noreply.github.com>2022-07-25 22:05:08 +0300
committerGitHub <noreply@github.com>2022-07-25 22:05:08 +0300
commit8062da23348a1c94ab9a4f3937e976f558e6bbdf (patch)
tree8d27dc4e3c7ed7f006b56307d793fb2d2aa6aae2
parentd43429388a10db7469bbda830d3534298215151e (diff)
DynamicallyAccessedMembers CodeFix (#2890)
* Create infrastructure for CodeFixers that will generate attribute flags for DynamicallyAccessedMembers (DAM) trimmer warnings. This commit includes fixers for the warnings `DynamicallyAccessedMembersMismatchParameterTargetsThisParameter` and `DynamicallyAccessedMembersMismatchFieldTargetsThisParameter`. Additional DiagnosticIds will be supported by future commits. * Create new class for the DAM CodeFixer that does not rely on base class. The DAM warnings require different attribute placement depending on the type of warning that is raised, causing it to differ from the implementation of the base class. * Added a test file specifically for the DAM CodeFixer, include tests for the functional fixes as well as tests for fixes that will soon be implemented. * Converted all test cases within DAM to use string literals Co-authored-by: Andy Gocke <andy@commentout.net>
-rw-r--r--src/ILLink.CodeFix/DAMCodeFixProvider.cs134
-rw-r--r--src/ILLink.CodeFix/Resources.resx3
-rw-r--r--src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs10
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs1297
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs678
5 files changed, 1488 insertions, 634 deletions
diff --git a/src/ILLink.CodeFix/DAMCodeFixProvider.cs b/src/ILLink.CodeFix/DAMCodeFixProvider.cs
new file mode 100644
index 000000000..60de66cea
--- /dev/null
+++ b/src/ILLink.CodeFix/DAMCodeFixProvider.cs
@@ -0,0 +1,134 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using ILLink.CodeFixProvider;
+using ILLink.RoslynAnalyzer;
+using ILLink.Shared;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Simplification;
+
+namespace ILLink.CodeFix
+{
+ public class DAMCodeFixProvider : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider
+ {
+ public static ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnostics ()
+ {
+ var diagDescriptorsArrayBuilder = ImmutableArray.CreateBuilder<DiagnosticDescriptor> ();
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter));
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter));
+ return diagDescriptorsArrayBuilder.ToImmutable ();
+ }
+
+ public static ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => GetSupportedDiagnostics ();
+
+ public sealed override ImmutableArray<string> FixableDiagnosticIds => SupportedDiagnostics.Select (dd => dd.Id).ToImmutableArray ();
+
+ private protected static LocalizableString CodeFixTitle => new LocalizableResourceString (nameof (Resources.DynamicallyAccessedMembersCodeFixTitle), Resources.ResourceManager, typeof (Resources));
+
+ private protected static string FullyQualifiedAttributeName => DynamicallyAccessedMembersAnalyzer.FullyQualifiedDynamicallyAccessedMembersAttribute;
+
+ protected static SyntaxNode[] GetAttributeArguments (ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
+ {
+ object id = Enum.Parse (typeof (DiagnosticId), diagnostic.Id.Substring (2));
+ switch (id) {
+ case DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter:
+ return new[] { syntaxGenerator.AttributeArgument (syntaxGenerator.TypedConstantExpression (targetSymbol.GetAttributes ().First (attr => attr.AttributeClass?.ToDisplayString () == DynamicallyAccessedMembersAnalyzer.FullyQualifiedDynamicallyAccessedMembersAttribute).ConstructorArguments[0])) };
+ case DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter:
+ return new[] { syntaxGenerator.AttributeArgument (syntaxGenerator.TypedConstantExpression (targetSymbol.GetAttributes ().First (attr => attr.AttributeClass?.ToDisplayString () == DynamicallyAccessedMembersAnalyzer.FullyQualifiedDynamicallyAccessedMembersAttribute).ConstructorArguments[0])) };
+ default:
+ return Array.Empty<SyntaxNode> ();
+ }
+ }
+
+ public sealed override FixAllProvider GetFixAllProvider ()
+ {
+ // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
+ return WellKnownFixAllProviders.BatchFixer;
+ }
+
+ public override async Task RegisterCodeFixesAsync (CodeFixContext context)
+ {
+ var document = context.Document;
+ if (await document.GetSyntaxRootAsync (context.CancellationToken).ConfigureAwait (false) is not { } root)
+ return;
+ var diagnostic = context.Diagnostics.First ();
+ SyntaxNode diagnosticNode = root.FindNode (diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ if (await document.GetSemanticModelAsync (context.CancellationToken).ConfigureAwait (false) is not { } model)
+ return;
+ // Note: We get the target symbol from the diagnostic location.
+ // This works when the diagnostic location is a method call, because the target symbol will be the called method with annotations, but won't work in general for other kinds of diagnostics.
+ if (model.GetSymbolInfo (diagnosticNode).Symbol is not { } targetSymbol)
+ return;
+ if (model.Compilation.GetTypeByMetadataName (FullyQualifiedAttributeName) is not { } attributeSymbol)
+ return;
+
+ if (diagnosticNode is not InvocationExpressionSyntax invocationExpression)
+ return;
+
+ var arguments = invocationExpression.ArgumentList.Arguments;
+
+ if (arguments.Count > 1)
+ return;
+
+ if (arguments.Count == 1) {
+ if (arguments[0].Expression is not LiteralExpressionSyntax literalSyntax
+ || literalSyntax.Kind () is not SyntaxKind.StringLiteralExpression) {
+ return;
+ }
+ }
+
+ // N.B. May be null for FieldDeclaration, since field declarations can declare multiple variables
+ var attributableSymbol = (invocationExpression.Expression is MemberAccessExpressionSyntax simpleMember
+ && simpleMember.Expression is IdentifierNameSyntax name) ? model.GetSymbolInfo (name).Symbol : null;
+
+
+ if (attributableSymbol is null)
+ return;
+
+ var attributableNodeList = attributableSymbol.DeclaringSyntaxReferences;
+
+ if (attributableNodeList.Length != 1)
+ return;
+
+ var attributableNode = attributableNodeList[0].GetSyntax ();
+
+ if (attributableNode is null) return;
+
+ var attributeArguments = GetAttributeArguments (targetSymbol, SyntaxGenerator.GetGenerator (document), diagnostic);
+ var codeFixTitle = CodeFixTitle.ToString ();
+
+ context.RegisterCodeFix (CodeAction.Create (
+ title: codeFixTitle,
+ createChangedDocument: ct => AddAttributeAsync (
+ document, attributableNode, attributeArguments, attributeSymbol, ct),
+ equivalenceKey: codeFixTitle), diagnostic);
+ }
+
+ private static async Task<Document> AddAttributeAsync (
+ Document document,
+ SyntaxNode targetNode,
+ SyntaxNode[] attributeArguments,
+ ITypeSymbol attributeSymbol,
+ CancellationToken cancellationToken)
+ {
+ var editor = await DocumentEditor.CreateAsync (document, cancellationToken).ConfigureAwait (false);
+ var generator = editor.Generator;
+ var attribute = generator.Attribute (
+ generator.TypeExpression (attributeSymbol), attributeArguments)
+ .WithAdditionalAnnotations (Simplifier.Annotation, Simplifier.AddImportsAnnotation);
+
+ editor.AddAttribute (targetNode, attribute);
+ return editor.GetChangedDocument ();
+ }
+ }
+}
diff --git a/src/ILLink.CodeFix/Resources.resx b/src/ILLink.CodeFix/Resources.resx
index 6105f1c1e..1e674b631 100644
--- a/src/ILLink.CodeFix/Resources.resx
+++ b/src/ILLink.CodeFix/Resources.resx
@@ -129,4 +129,7 @@
<data name="UconditionalSuppressMessageCodeFixTitle" xml:space="preserve">
<value>Add UnconditionalSuppressMessage attribute to parent method</value>
</data>
+ <data name="DynamicallyAccessedMembersCodeFixTitle" xml:space="preserve">
+ <value>Add DynamicallyAccessedMembers attribute to source of warning</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
index 0c93e3f62..0e095dbc5 100644
--- a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
+++ b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
@@ -22,8 +22,9 @@ namespace ILLink.RoslynAnalyzer
{
internal const string DynamicallyAccessedMembers = nameof (DynamicallyAccessedMembers);
internal const string DynamicallyAccessedMembersAttribute = nameof (DynamicallyAccessedMembersAttribute);
+ public const string FullyQualifiedDynamicallyAccessedMembersAttribute = "System.Diagnostics.CodeAnalysis." + DynamicallyAccessedMembersAttribute;
- static ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnostics ()
+ public static ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnostics ()
{
var diagDescriptorsArrayBuilder = ImmutableArray.CreateBuilder<DiagnosticDescriptor> (26);
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresUnreferencedCode));
@@ -114,12 +115,12 @@ namespace ILLink.RoslynAnalyzer
var symbol = context.SemanticModel.GetSymbolInfo (context.Node).Symbol;
- // Avoid unnecesary execution if not NamedType or Method
+ // Avoid unnecessary execution if not NamedType or Method
if (symbol is not INamedTypeSymbol && symbol is not IMethodSymbol)
return;
// Members inside nameof or cref comments, commonly used to access the string value of a variable, type, or a memeber,
- // can generate diagnostics warnings, which can be noisy and unhelpful.
+ // can generate diagnostics warnings, which can be noisy and unhelpful.
// Walking the node heirarchy to check if the member is inside a nameof/cref to not generate diagnostics
var parentNode = context.Node;
while (parentNode != null) {
@@ -210,11 +211,12 @@ namespace ILLink.RoslynAnalyzer
method.Locations[0], method.GetDisplayName (), overriddenMethod.GetDisplayName ()));
for (int i = 0; i < method.Parameters.Length; i++) {
- if (FlowAnnotations.GetMethodParameterAnnotation (method.Parameters[i]) != FlowAnnotations.GetMethodParameterAnnotation (overriddenMethod.Parameters[i]))
+ if (FlowAnnotations.GetMethodParameterAnnotation (method.Parameters[i]) != FlowAnnotations.GetMethodParameterAnnotation (overriddenMethod.Parameters[i])) {
context.ReportDiagnostic (Diagnostic.Create (
DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides),
method.Parameters[i].Locations[0],
method.Parameters[i].GetDisplayName (), method.GetDisplayName (), overriddenMethod.Parameters[i].GetDisplayName (), overriddenMethod.GetDisplayName ()));
+ }
}
for (int i = 0; i < method.TypeParameters.Length; i++) {
diff --git a/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
index 4d0109638..90a7de166 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
@@ -5,8 +5,9 @@ using System.Threading.Tasks;
using ILLink.Shared;
using Microsoft.CodeAnalysis.Testing;
using Xunit;
-using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier<
- ILLink.RoslynAnalyzer.DynamicallyAccessedMembersAnalyzer>;
+using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpCodeFixVerifier<
+ ILLink.RoslynAnalyzer.DynamicallyAccessedMembersAnalyzer,
+ ILLink.CodeFix.DAMCodeFixProvider>;
namespace ILLink.RoslynAnalyzer.Tests
{
@@ -22,31 +23,32 @@ namespace ILLink.RoslynAnalyzer.Tests
[Fact]
public Task NoWarningsIfAnalyzerIsNotEnabled ()
{
- var TargetParameterWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetParameterWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
- private static void NeedsPublicMethodsOnParameter(
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type parameter)
- {
- }
+ private static void NeedsPublicMethodsOnParameter(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type parameter)
+ {
+ }
- private static void M(Type type)
- {
- NeedsPublicMethodsOnParameter(type);
- }
-}";
+ private static void M(Type type)
+ {
+ NeedsPublicMethodsOnParameter(type);
+ }
+ }
+ """;
return VerifyCS.VerifyAnalyzerAsync (TargetParameterWithAnnotations);
}
@@ -54,37 +56,37 @@ class C
[Fact]
public Task SourceParameterDoesNotMatchTargetParameterAnnotations ()
{
- var TargetParameterWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-public class Foo
-{
-}
+ var TargetParameterWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
+ public class Foo
+ {
+ }
- private static void NeedsPublicMethodsOnParameter(
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type parameter)
- {
- }
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+ private static void NeedsPublicMethodsOnParameter(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type parameter)
+ {
+ }
- private static void M(Type type)
- {
- NeedsPublicMethodsOnParameter(type);
- }
-}";
- // (23,3): warning IL2067: 'parameter' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethodsOnParameter(Type)'.
+ private static void M(Type type)
+ {
+ NeedsPublicMethodsOnParameter(type);
+ }
+ }
+ """;
+ // (21,3): warning IL2067: 'parameter' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethodsOnParameter(Type)'.
// The parameter 'type' of method 'C.M(Type)' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter)
- .WithSpan (23, 3, 23, 38)
+ .WithSpan (21, 3, 21, 38)
.WithArguments ("parameter",
"C.NeedsPublicMethodsOnParameter(Type)",
"type",
@@ -95,34 +97,35 @@ class C
[Fact]
public Task SourceParameterDoesNotMatchTargetMethodReturnTypeAnnotations ()
{
- var TargetMethodReturnTypeWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetMethodReturnTypeWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
-
- [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type M(Type type)
- {
- return type;
- }
-}";
-
- // (19,9): warning IL2068: 'C.M(Type)' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type M(Type type)
+ {
+ return type;
+ }
+ }
+ """;
+
+ // (18,10): warning IL2068: 'C.M(Type)' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The parameter 'type' of method 'C.M(Type)' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType)
- .WithSpan (19, 16, 19, 20)
+ .WithSpan (18, 10, 18, 14)
.WithArguments ("C.M(Type)",
"type",
"C.M(Type)",
@@ -132,36 +135,37 @@ class C
[Fact]
public Task SourceParameterDoesNotMatchTargetFieldAnnotations ()
{
- var TargetFieldWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetFieldWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
- private static void M(Type type)
- {
- f = type;
- }
+ private static void M(Type type)
+ {
+ f = type;
+ }
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type f = typeof(Foo);
-}";
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f = typeof(Foo);
+ }
+ """;
- // (18,9): warning IL2069: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ // (17,3): warning IL2069: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The parameter 'type' of method 'C.M(Type)' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField)
- .WithSpan (18, 9, 18, 17)
+ .WithSpan (17, 3, 17, 11)
.WithArguments ("C.f",
"type",
"C.M(Type)",
@@ -171,33 +175,34 @@ class C
[Fact]
public Task SourceParameterDoesNotMatchTargetMethodAnnotations ()
{
- var TargetMethodWithAnnotations = @"
-using System;
+ var TargetMethodWithAnnotations = $$"""
+ using System;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
-
- private static void M(Type type)
- {
- type.GetMethod(""Bar"");
- }
-}";
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+
+ private static void M(Type type)
+ {
+ type.GetMethod("Bar");
+ }
+ }
+ """;
// The warning will be generated once dataflow is able to handle GetMethod intrinsic
- // (17,9): warning IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
+ // (16,3): warning IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
// The parameter 'type' of method 'C.M(Type)' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter)
- .WithSpan (17, 9, 17, 30)
+ .WithSpan (16, 3, 16, 24)
.WithArguments ("System.Type.GetMethod(String)",
"type",
"C.M(Type)",
@@ -209,113 +214,116 @@ class C
[Fact]
public Task SourceMethodReturnTypeDoesNotMatchTargetParameterAnnotations ()
{
- var TargetParameterWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetParameterWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class T
-{
-}
+ public class T
+ {
+ }
-class C
-{
- public static void Main()
- {
- NeedsPublicMethodsOnParameter(GetT());
- }
-
- private static void NeedsPublicMethodsOnParameter(
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
-
- private static Type GetT()
- {
- return typeof(T);
- }
-}";
-
- // (13,9): warning IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethodsOnParameter(Type)'.
+ class C
+ {
+ public static void Main()
+ {
+ NeedsPublicMethodsOnParameter(GetT());
+ }
+
+ private static void NeedsPublicMethodsOnParameter(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+
+ private static Type GetT()
+ {
+ return typeof(T);
+ }
+ }
+ """;
+
+ // (12,3): warning IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethodsOnParameter(Type)'.
// The return value of method 'C.GetT()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter)
- .WithSpan (13, 9, 13, 46)
+ .WithSpan (12, 3, 12, 40)
.WithArguments ("type", "C.NeedsPublicMethodsOnParameter(Type)", "C.GetT()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
[Fact]
public Task SourceMethodReturnTypeDoesNotMatchTargetMethodReturnTypeAnnotations ()
{
- var TargetMethodReturnTypeWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetMethodReturnTypeWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M();
- }
-
- [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type M()
- {
- return GetFoo();
- }
-
- private static Type GetFoo()
- {
- return typeof(Foo);
- }
-}";
-
- // (19,9): warning IL2073: 'C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ class C
+ {
+ public static void Main()
+ {
+ M();
+ }
+
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type M()
+ {
+ return GetFoo();
+ }
+
+ private static Type GetFoo()
+ {
+ return typeof(Foo);
+ }
+ }
+ """;
+
+ // (18,10): warning IL2073: 'C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The return value of method 'C.GetT()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsMethodReturnType)
- .WithSpan (19, 16, 19, 24)
+ .WithSpan (18, 10, 18, 18)
.WithArguments ("C.M()", "C.GetFoo()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
[Fact]
public Task SourceMethodReturnTypeDoesNotMatchTargetFieldAnnotations ()
{
- var TargetFieldWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetFieldWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- f = M();
- }
+ class C
+ {
+ public static void Main()
+ {
+ f = M();
+ }
- private static Type M()
- {
- return typeof(Foo);
- }
+ private static Type M()
+ {
+ return typeof(Foo);
+ }
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type f;
-}";
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f;
+ }
+ """;
- // (13,9): warning IL2074: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ // (12,3): warning IL2074: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The return value of method 'C.M()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsField)
- .WithSpan (13, 9, 13, 16)
+ .WithSpan (12, 3, 12, 10)
.WithArguments ("C.f",
"C.M()",
"'DynamicallyAccessedMemberTypes.PublicMethods'"));
@@ -324,34 +332,35 @@ class C
[Fact]
public Task SourceMethodReturnTypeDoesNotMatchTargetMethod ()
{
- var TargetMethodWithAnnotations = @"
-using System;
+ var TargetMethodWithAnnotations = $$"""
+ using System;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- GetFoo().GetMethod(""Bar"");
+ class C
+ {
+ public static void Main()
+ {
+ GetFoo().GetMethod("Bar");
- }
+ }
- private static Type GetFoo ()
- {
- return typeof (Foo);
- }
-}";
+ private static Type GetFoo ()
+ {
+ return typeof (Foo);
+ }
+ }
+ """;
// The warning will be generated once dataflow is able to handle GetMethod intrinsic
- // (12,9): warning IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
+ // (11,3): warning IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
// The return value of method 'C.GetT()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter)
- .WithSpan (12, 9, 12, 34)
+ .WithSpan (11, 3, 11, 28)
.WithArguments ("System.Type.GetMethod(String)", "C.GetFoo()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
#endregion
@@ -360,35 +369,36 @@ class C
[Fact]
public Task SourceFieldDoesNotMatchTargetParameterAnnotations ()
{
- var TargetParameterWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetParameterWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- private static Type f = typeof(Foo);
+ class C
+ {
+ private static Type f = typeof(Foo);
- public static void Main()
- {
- NeedsPublicMethods(f);
- }
+ public static void Main()
+ {
+ NeedsPublicMethods(f);
+ }
- private static void NeedsPublicMethods(
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
-}";
+ private static void NeedsPublicMethods(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+ }
+ """;
- // (15,9): warning IL2077: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethods(Type)'.
+ // (14,3): warning IL2077: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethods(Type)'.
// The field 'C.f' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsParameter)
- .WithSpan (15, 9, 15, 30)
+ .WithSpan (14, 3, 14, 24)
.WithArguments ("type",
"C.NeedsPublicMethods(Type)",
"C.f",
@@ -398,36 +408,37 @@ class C
[Fact]
public Task SourceFieldDoesNotMatchTargetMethodReturnTypeAnnotations ()
{
- var TargetMethodReturnTypeWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetMethodReturnTypeWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- private static Type f = typeof(Foo);
+ class C
+ {
+ private static Type f = typeof(Foo);
- public static void Main()
- {
- M();
- }
+ public static void Main()
+ {
+ M();
+ }
- [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type M()
- {
- return f;
- }
-}";
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type M()
+ {
+ return f;
+ }
+ }
+ """;
- // (21,9): warning IL2078: 'C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ // (20,10): warning IL2078: 'C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The field 'C.f' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsMethodReturnType)
- .WithSpan (21, 16, 21, 17)
+ .WithSpan (20, 10, 20, 11)
.WithArguments ("C.M()", "C.f",
"'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
@@ -435,32 +446,33 @@ class C
[Fact]
public Task SourceFieldDoesNotMatchTargetFieldAnnotations ()
{
- var TargetFieldWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetFieldWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- private static Type f1 = typeof(Foo);
+ class C
+ {
+ private static Type f1 = typeof(Foo);
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type f2 = typeof(Foo);
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f2 = typeof(Foo);
- public static void Main()
- {
- f2 = f1;
- }
-}";
- // (18,9): warning IL2079: value stored in field 'C.f2' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ public static void Main()
+ {
+ f2 = f1;
+ }
+ }
+ """;
+ // (17,3): warning IL2079: value stored in field 'C.f2' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The field 'C.f1' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsField)
- .WithSpan (18, 9, 18, 16)
+ .WithSpan (17, 3, 17, 10)
.WithArguments ("C.f2",
"C.f1",
"'DynamicallyAccessedMemberTypes.PublicMethods'"));
@@ -469,30 +481,31 @@ class C
[Fact]
public Task SourceFieldDoesNotMatchTargetMethodAnnotations ()
{
- var TargetMethodWithAnnotations = @"
-using System;
+ var TargetMethodWithAnnotations = $$"""
+ using System;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- private static Type f = typeof(Foo);
+ class C
+ {
+ private static Type f = typeof(Foo);
- public static void Main()
- {
- f.GetMethod(""Bar"");
- }
-}";
+ public static void Main()
+ {
+ f.GetMethod("Bar");
+ }
+ }
+ """;
// The warning will be generated once dataflow is able to handle GetMethod intrinsic
- // (14,9): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
+ // (13,3): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
// The field 'C.f' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter)
- .WithSpan (14, 9, 14, 27)
+ .WithSpan (13, 3, 13, 21)
.WithArguments ("System.Type.GetMethod(String)",
"C.f",
"'DynamicallyAccessedMemberTypes.PublicMethods'"));
@@ -503,7 +516,7 @@ class C
static string GetSystemTypeBase ()
{
- return @"
+ return $$"""
// 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.
@@ -641,7 +654,7 @@ namespace System
throw new NotImplementedException ();
}
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors
| DynamicallyAccessedMemberTypes.NonPublicConstructors)]
protected override ConstructorInfo GetConstructorImpl (BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
{
@@ -690,78 +703,82 @@ namespace System
throw new NotImplementedException ();
}
}
-}";
+}
+""";
}
[Fact]
public Task SourceMethodDoesNotMatchTargetParameterAnnotations ()
{
- var TargetParameterWithAnnotations = @"
-namespace System
-{
- class C : TestSystemTypeBase
- {
- public static void Main()
- {
- new C().M1();
- }
-
- private void M1()
- {
- M2(this);
- }
-
- private static void M2(
- [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
- }
-}";
-
- // (200,16): warning IL2082: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'.
+ var TargetParameterWithAnnotations = $$"""
+ namespace System
+ {
+ class C : TestSystemTypeBase
+ {
+ public static void Main()
+ {
+ new C().M1();
+ }
+
+ private void M1()
+ {
+ M2(this);
+ }
+
+ private static void M2(
+ [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+ }
+ }
+ """;
+
+ // (198,4): warning IL2082: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'.
// The implicit 'this' argument of method 'System.C.M1()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetParameterWithAnnotations),
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsParameter)
- .WithSpan (200, 13, 200, 21)
+ .WithSpan (198, 4, 198, 12)
.WithArguments ("type", "System.C.M2(Type)", "System.C.M1()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
[Fact]
public Task ConversionOperation ()
{
- var ConversionOperation = @"
-namespace System
-{
- class ConvertsToType
- {
- public static implicit operator Type(ConvertsToType value) => typeof (ConvertsToType);
- }
-
- class C : TestSystemTypeBase
- {
- public static void Main()
- {
- new C().M1();
- }
-
- private void M1()
- {
- M2(new ConvertsToType());
- }
-
- private static void M2(
- [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
- }
-}";
+ var ConversionOperation = $$"""
+ namespace System
+ {
+ class ConvertsToType
+ {
+ public static implicit operator Type(ConvertsToType value) => typeof (ConvertsToType);
+ }
+
+ class C : TestSystemTypeBase
+ {
+ public static void Main()
+ {
+ new C().M1();
+ }
+
+ private void M1()
+ {
+ M2(new ConvertsToType());
+ }
+
+ private static void M2(
+ [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+ }
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), ConversionOperation),
+ // (203,4): warning IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'. The return value of method 'System.ConvertsToType.implicit operator Type(ConvertsToType)' 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.
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter)
- .WithSpan (205, 13, 205, 37)
+ .WithSpan (203, 4, 203, 28)
.WithArguments ("type", "System.C.M2(Type)", "System.ConvertsToType.implicit operator Type(ConvertsToType)", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
@@ -769,74 +786,77 @@ namespace System
[Fact]
public Task ConversionOperationAnnotationDoesNotMatch ()
{
- var AnnotatedConversionOperation = @"
-namespace System
-{
- class ConvertsToType
- {
- [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)]
- public static implicit operator Type(ConvertsToType value) => null;
- }
-
- class C : TestSystemTypeBase
- {
- public static void Main()
- {
- new C().M1();
- }
-
- private void M1()
- {
- M2(new ConvertsToType());
- }
-
- private static void M2(
- [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
- }
-}";
+ var AnnotatedConversionOperation = $$"""
+ namespace System
+ {
+ class ConvertsToType
+ {
+ [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)]
+ public static implicit operator Type(ConvertsToType value) => null;
+ }
+
+ class C : TestSystemTypeBase
+ {
+ public static void Main()
+ {
+ new C().M1();
+ }
+
+ private void M1()
+ {
+ M2(new ConvertsToType());
+ }
+
+ private static void M2(
+ [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+ }
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), AnnotatedConversionOperation),
+ // (205,4): warning IL2072: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'. The return value of method 'System.ConvertsToType.implicit operator Type(ConvertsToType)' 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.
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter)
- .WithSpan (207, 13, 207, 37)
+ .WithSpan (205, 4, 205, 28)
.WithArguments ("type", "System.C.M2(Type)", "System.ConvertsToType.implicit operator Type(ConvertsToType)", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
[Fact]
public Task ConversionOperationAnnotationMatches ()
{
- var AnnotatedConversionOperation = @"
-namespace System
-{
- class ConvertsToType
- {
- [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
- public static implicit operator Type(ConvertsToType value) => null;
- }
-
- class C : TestSystemTypeBase
- {
- public static void Main()
- {
- new C().M1();
- }
-
- private void M1()
- {
- M2(new ConvertsToType());
- }
-
- private static void M2(
- [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
- }
-}";
+ var AnnotatedConversionOperation = $$"""
+ namespace System
+ {
+ class ConvertsToType
+ {
+ [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
+ public static implicit operator Type(ConvertsToType value) => null;
+ }
+
+ class C : TestSystemTypeBase
+ {
+ public static void Main()
+ {
+ new C().M1();
+ }
+
+ private void M1()
+ {
+ M2(new ConvertsToType());
+ }
+
+ private static void M2(
+ [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+ }
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), AnnotatedConversionOperation));
}
@@ -845,64 +865,66 @@ namespace System
[Fact]
public Task SourceMethodDoesNotMatchTargetMethodReturnTypeAnnotations ()
{
- var TargetMethodReturnTypeWithAnnotations = @"
-namespace System
-{
- class C : TestSystemTypeBase
- {
- public static void Main()
- {
- new C().M();
- }
-
- [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
- private Type M()
- {
- return this;
- }
- }
-}";
-
- // (202,13): warning IL2083: 'System.C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ var TargetMethodReturnTypeWithAnnotations = $$"""
+ namespace System
+ {
+ class C : TestSystemTypeBase
+ {
+ public static void Main()
+ {
+ new C().M();
+ }
+
+ [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
+ private Type M()
+ {
+ return this;
+ }
+ }
+ }
+ """;
+
+ // (200,11): warning IL2083: 'System.C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The implicit 'this' argument of method 'System.C.M()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetMethodReturnTypeWithAnnotations),
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsMethodReturnType)
- .WithSpan (202, 20, 202, 24)
+ .WithSpan (200, 11, 200, 15)
.WithArguments ("System.C.M()", "System.C.M()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
[Fact]
public Task SourceMethodDoesNotMatchTargetFieldAnnotations ()
{
- var TargetFieldWithAnnotations = @"
-namespace System
-{
- class C : TestSystemTypeBase
- {
- public static void Main()
- {
- new C().M();
- }
-
- private void M()
- {
- f = this;
- }
-
- [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
- System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type f;
- }
-}";
-
- // (200,13): warning IL2084: value stored in field 'System.C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ var TargetFieldWithAnnotations = $$"""
+ namespace System
+ {
+ class C : TestSystemTypeBase
+ {
+ public static void Main()
+ {
+ new C().M();
+ }
+
+ private void M()
+ {
+ f = this;
+ }
+
+ [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
+ System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f;
+ }
+ }
+ """;
+
+ // (198,4): warning IL2084: value stored in field 'System.C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The implicit 'this' argument of method 'System.C.M()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetFieldWithAnnotations),
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsField)
- .WithSpan (200, 13, 200, 21)
+ .WithSpan (198, 4, 198, 12)
.WithArguments ("System.C.f",
"System.C.M()",
"'DynamicallyAccessedMemberTypes.PublicMethods'"));
@@ -911,29 +933,30 @@ namespace System
[Fact]
public Task SourceMethodDoesNotMatchTargetMethodAnnotations ()
{
- var TargetMethodWithAnnotations = @"
-namespace System
-{
- class C : TestSystemTypeBase
- {
- public static void Main()
- {
- new C().M();
- }
-
- private void M()
- {
- this.GetMethods();
- }
- }
-}";
-
- // (200,13): warning IL2085: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'.
+ var TargetMethodWithAnnotations = $$"""
+ namespace System
+ {
+ class C : TestSystemTypeBase
+ {
+ public static void Main()
+ {
+ new C().M();
+ }
+
+ private void M()
+ {
+ this.GetMethods();
+ }
+ }
+ }
+ """;
+
+ // (198,4): warning IL2085: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'.
// The implicit 'this' argument of method 'System.C.M()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), TargetMethodWithAnnotations),
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchThisParameterTargetsThisParameter)
- .WithSpan (200, 13, 200, 30)
+ .WithSpan (198, 4, 198, 21)
.WithArguments ("System.Type.GetMethods()", "System.C.M()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
#endregion
@@ -941,96 +964,99 @@ namespace System
[Fact]
public Task SourceGenericParameterDoesNotMatchTargetParameterAnnotations ()
{
- var TargetParameterWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetParameterWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-class C
-{
- public static void Main()
- {
- M2<int>();
- }
-
- private static void M1(
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
-
- private static void M2<T>()
- {
- M1(typeof(T));
- }
-}";
-
- // (19,9): warning IL2087: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.M1(Type)'.
+ class C
+ {
+ public static void Main()
+ {
+ M2<int>();
+ }
+
+ private static void M1(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+
+ private static void M2<T>()
+ {
+ M1(typeof(T));
+ }
+ }
+ """;
+
+ // (18,3): warning IL2087: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.M1(Type)'.
// The generic parameter 'T' of 'C.M2<T>()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsParameter)
- .WithSpan (19, 9, 19, 22)
+ .WithSpan (18, 3, 18, 16)
.WithArguments ("type", "C.M1(Type)", "T", "C.M2<T>()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
[Fact]
public Task SourceGenericParameterDoesNotMatchTargetMethodReturnTypeAnnotations ()
{
- var TargetMethodReturnTypeWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetMethodReturnTypeWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-class C
-{
- public static void Main()
- {
- M<int>();
- }
-
- [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
- private static Type M<T>()
- {
- return typeof(T);
- }
-}";
-
- // (15,9): warning IL2088: 'C.M<T>()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' requirements.
+ class C
+ {
+ public static void Main()
+ {
+ M<int>();
+ }
+
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
+ private static Type M<T>()
+ {
+ return typeof(T);
+ }
+ }
+ """;
+
+ // (14,10): warning IL2088: 'C.M<T>()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicConstructors' requirements.
// The generic parameter 'T' of 'C.M<T>()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsMethodReturnType)
- .WithSpan (15, 16, 15, 25)
+ .WithSpan (14, 10, 14, 19)
.WithArguments ("C.M<T>()", "T", "C.M<T>()", "'DynamicallyAccessedMemberTypes.PublicConstructors'"));
}
[Fact]
public Task SourceGenericParameterDoesNotMatchTargetFieldAnnotations ()
{
- var TargetFieldWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetFieldWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-class C
-{
- public static void Main()
- {
- M<int>();
- }
+ class C
+ {
+ public static void Main()
+ {
+ M<int>();
+ }
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type f;
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f;
- private static void M<T>()
- {
- f = typeof(T);
- }
-}";
+ private static void M<T>()
+ {
+ f = typeof(T);
+ }
+ }
+ """;
- // (17,9): warning IL2089: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ // (16,3): warning IL2089: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
// The generic parameter 'T' of 'C.M<T>()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsField)
- .WithSpan (17, 9, 17, 22)
+ .WithSpan (16, 3, 16, 16)
.WithArguments ("C.f",
"T",
"C.M<T>()",
@@ -1040,84 +1066,87 @@ class C
[Fact]
public Task SourceGenericParameterDoesNotMatchTargetGenericParameterAnnotations ()
{
- var TargetGenericParameterWithAnnotations = @"
-using System.Diagnostics.CodeAnalysis;
+ var TargetGenericParameterWithAnnotations = $$"""
+ using System.Diagnostics.CodeAnalysis;
-class C
-{
- public static void Main()
- {
- M2<int>();
- }
-
- private static void M1<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>()
- {
- }
-
- private static void M2<S>()
- {
- M1<S>();
- }
-}";
-
- // (17,9): warning IL2091: 'T' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods'
+ class C
+ {
+ public static void Main()
+ {
+ M2<int>();
+ }
+
+ private static void M1<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>()
+ {
+ }
+
+ private static void M2<S>()
+ {
+ M1<S>();
+ }
+ }
+ """;
+
+ // (16,3): warning IL2091: 'T' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods'
// in 'C.M1<T>()'. The generic parameter 'S' of 'C.M2<S>()' 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.
return VerifyDynamicallyAccessedMembersAnalyzer (TargetGenericParameterWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter)
- .WithSpan (17, 9, 17, 14)
+ .WithSpan (16, 3, 16, 8)
.WithArguments ("T", "C.M1<T>()", "S", "C.M2<S>()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
[Fact]
public Task SourceTypeofFlowsIntoTargetParameterAnnotations ()
{
- var TargetParameterWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetParameterWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
-
- private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- }
-}";
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+
+ private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ }
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (TargetParameterWithAnnotations);
}
[Fact]
public Task SourceTypeofFlowsIntoTargetMethodReturnTypeAnnotation ()
{
- var TargetMethodReturnTypeWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetMethodReturnTypeWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M();
- }
-
- [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type M()
- {
- return typeof(Foo);
- }
-}";
+ class C
+ {
+ public static void Main()
+ {
+ M();
+ }
+
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type M()
+ {
+ return typeof(Foo);
+ }
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations);
}
@@ -1125,27 +1154,28 @@ class C
[Fact]
public Task SourceParameterFlowsInfoTargetMethodReturnTypeAnnotations ()
{
- var TargetMethodReturnTypeWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetMethodReturnTypeWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
-
- [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- return type;
- }
-}";
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ return type;
+ }
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodReturnTypeWithAnnotations);
}
@@ -1153,29 +1183,30 @@ class C
[Fact]
public Task SourceParameterFlowsIntoTargetFieldAnnotations ()
{
- var TargetFieldWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetFieldWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
- private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- f = type;
- }
+ private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ f = type;
+ }
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
- private static Type f = typeof(Foo);
-}";
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f = typeof(Foo);
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (TargetFieldWithAnnotations);
}
@@ -1183,26 +1214,27 @@ class C
[Fact]
public Task SourceParameterFlowsIntoTargetMethodAnnotations ()
{
- var TargetMethodWithAnnotations = @"
-using System;
-using System.Diagnostics.CodeAnalysis;
+ var TargetMethodWithAnnotations = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
-public class Foo
-{
-}
+ public class Foo
+ {
+ }
-class C
-{
- public static void Main()
- {
- M(typeof(Foo));
- }
-
- private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
- {
- type.GetMethod(""Bar"");
- }
-}";
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+
+ private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ {
+ type.GetMethod("Bar");
+ }
+ }
+ """;
return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations);
}
@@ -1226,6 +1258,7 @@ class C
""";
return VerifyDynamicallyAccessedMembersAnalyzer (Source,
+ // (8,14): error CS0103: The name 'type' does not exist in the current context
DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 14, 8, 18).WithArguments ("type"));
}
@@ -1242,13 +1275,14 @@ class C
{
GetTypeWithAll ();
}
-
+
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
static Type GetTypeWithAll() => type;
}
""";
return VerifyDynamicallyAccessedMembersAnalyzer (Source,
+ // (12,34): error CS0103: The name 'type' does not exist in the current context
DiagnosticResult.CompilerError ("CS0103").WithSpan (12, 34, 12, 38).WithArguments ("type"));
}
@@ -1265,13 +1299,14 @@ class C
{
fieldRequiresAll = type;
}
-
+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
static Type fieldRequiresAll;
}
""";
return VerifyDynamicallyAccessedMembersAnalyzer (Source,
+ // (8,22): error CS0103: The name 'type' does not exist in the current context
DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 22, 8, 26).WithArguments ("type"));
}
@@ -1288,13 +1323,14 @@ class C
{
type = GetTypeWithAll();
}
-
+
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
static Type GetTypeWithAll() => null;
}
""";
return VerifyDynamicallyAccessedMembersAnalyzer (Source,
+ // (8,9): error CS0103: The name 'type' does not exist in the current context
DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 3, 8, 7).WithArguments ("type"));
}
@@ -1311,13 +1347,14 @@ class C
{
type ??= GetTypeWithAll();
}
-
+
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
static Type GetTypeWithAll() => null;
}
""";
return VerifyDynamicallyAccessedMembersAnalyzer (Source,
+ // (8,3): error CS0103: The name 'type' does not exist in the current context
DiagnosticResult.CompilerError ("CS0103").WithSpan (8, 3, 8, 7).WithArguments ("type"));
}
}
diff --git a/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs
new file mode 100644
index 000000000..4bda78a88
--- /dev/null
+++ b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs
@@ -0,0 +1,678 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Threading.Tasks;
+using ILLink.Shared;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Text;
+using Xunit;
+using VerifyCS = ILLink.RoslynAnalyzer.Tests.CSharpCodeFixVerifier<
+ ILLink.RoslynAnalyzer.DynamicallyAccessedMembersAnalyzer,
+ ILLink.CodeFix.DAMCodeFixProvider>;
+
+namespace ILLink.RoslynAnalyzer.Tests
+{
+ public class DynamicallyAccessedMembersCodeFixTests
+ {
+ static Task VerifyDynamicallyAccessedMembersCodeFix (
+ string source,
+ string fixedSource,
+ DiagnosticResult[] baselineExpected,
+ DiagnosticResult[] fixedExpected,
+ int? numberOfIterations = null)
+ {
+ var test = new VerifyCS.Test {
+ TestCode = source,
+ FixedCode = fixedSource,
+ ReferenceAssemblies = TestCaseUtils.Net6PreviewAssemblies
+ };
+ test.ExpectedDiagnostics.AddRange (baselineExpected);
+ test.TestState.AnalyzerConfigFiles.Add (
+ ("/.editorconfig", SourceText.From (@$"
+is_global = true
+build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
+ if (numberOfIterations != null) {
+ test.NumberOfIncrementalIterations = numberOfIterations;
+ test.NumberOfFixAllIterations = numberOfIterations;
+ }
+ test.FixedState.ExpectedDiagnostics.AddRange (fixedExpected);
+ return test.RunAsync ();
+ }
+
+
+ [Fact]
+ public async Task CodeFix_IL2070_MismatchParamTargetsThisParam_PublicMethods ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(C));
+ }
+ static void M(Type t)
+ {
+ t.GetMethods();
+ }
+ }
+ """;
+ var fixtest = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(C));
+ }
+ static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t)
+ {
+ t.GetMethods();
+ }
+ }
+ """;
+ await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new[] {
+ // /0/Test0.cs(12,3): warning IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'.
+ // The parameter 't' of method 'C.M(Type)' 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.
+ VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter)
+ .WithSpan(12, 3, 12, 17)
+ .WithArguments("System.Type.GetMethods()",
+ "t",
+ "C.M(Type)",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'") },
+ fixedExpected: Array.Empty<DiagnosticResult> ());
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2070_ArgsTurnOffCodeFix ()
+ {
+ var test = $$"""
+ using System;
+ using System.Reflection;
+
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(C));
+ }
+ static void M(Type t)
+ {
+ t.GetMethods(BindingFlags.NonPublic);
+ }
+ }
+ """;
+ var diag = new[] {
+ // /0/Test0.cs(12,3): warning IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Type.GetMethods(BindingFlags)'.
+ // The parameter 't' of method 'C.M(Type)' 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.
+ VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter)
+ .WithSpan (12, 3, 12, 39)
+ .WithArguments ("System.Type.GetMethods(BindingFlags)",
+ "t",
+ "C.M(Type)",
+ "'DynamicallyAccessedMemberTypes.NonPublicMethods'") };
+ await VerifyDynamicallyAccessedMembersCodeFix (test, test, diag, diag);
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2070_GetMethodsInArg ()
+ {
+ var test = $$"""
+ using System.Reflection;
+ using System.Diagnostics.CodeAnalysis;
+
+ namespace System
+ {
+ static class C
+ {
+ static void Main(Type t)
+ {
+ DoSomethingWithMethods(t.GetMethods());
+ }
+
+ static void DoSomethingWithMethods(MethodInfo[] m)
+ {
+ }
+ }
+ }
+ """;
+
+ var fixtest = """
+ using System.Reflection;
+ using System.Diagnostics.CodeAnalysis;
+
+ namespace System
+ {
+ static class C
+ {
+ static void Main([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t)
+ {
+ DoSomethingWithMethods(t.GetMethods());
+ }
+
+ static void DoSomethingWithMethods(MethodInfo[] m)
+ {
+ }
+ }
+ }
+ """;
+
+ await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new[] {
+ // /0/Test0.cs(10,27): warning IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'. The parameter 't' of method 'System.C.Main(Type)' 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.
+ VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter).WithSpan(10, 27, 10, 41).WithArguments("System.Type.GetMethods()", "t", "System.C.Main(Type)", "'DynamicallyAccessedMemberTypes.PublicMethods'")},
+ fixedExpected: Array.Empty<DiagnosticResult> ());
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2080_MismatchFieldTargetsPrivateParam_PublicMethods ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ private static Type f = typeof(Foo);
+
+ public static void Main()
+ {
+ f.GetMethod("Bar");
+ }
+ }
+ """;
+ var fixtest = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f = typeof(Foo);
+
+ public static void Main()
+ {
+ f.GetMethod("Bar");
+ }
+ }
+ """;
+ await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new[] {
+ // /0/Test0.cs(13,3): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
+ // The field 'C.f' 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.
+ VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter)
+ .WithSpan(13, 3, 13, 21)
+ .WithArguments("System.Type.GetMethod(String)",
+ "C.f",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'")},
+ fixedExpected: Array.Empty<DiagnosticResult> ());
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2080_MismatchFieldTargetsPublicParam_PublicMethods ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ public static Type f = typeof(Foo);
+
+ public static void Main()
+ {
+ f.GetMethod("Bar");
+ }
+ }
+ """;
+ var fixtest = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ public static Type f = typeof(Foo);
+
+ public static void Main()
+ {
+ f.GetMethod("Bar");
+ }
+ }
+ """;
+ await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new[] {
+ // /0/Test0.cs(13,3): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
+ // The field 'C.f' 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.
+ VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter)
+ .WithSpan(13, 3, 13, 21)
+ .WithArguments("System.Type.GetMethod(String)",
+ "C.f",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'")},
+ fixedExpected: Array.Empty<DiagnosticResult> ());
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2080_MismatchFieldTargetsPublicParam_Int ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ public static Type f = typeof(Foo);
+
+ public static void Main()
+ {
+ f.GetMethod("Bar");
+ }
+ }
+ """;
+ var fixtest = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ public static Type f = typeof(Foo);
+
+ public static void Main()
+ {
+ f.GetMethod("Bar");
+ }
+ }
+ """;
+ await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new[] {
+ // /0/Test0.cs(13,3): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
+ // The field 'C.f' 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.
+ VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter)
+ .WithSpan(13, 3, 13, 21)
+ .WithArguments("System.Type.GetMethod(String)",
+ "C.f",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'")},
+ fixedExpected: Array.Empty<DiagnosticResult> ());
+ }
+
+ // these diagnosticIDs are currently unsupported, and as such will currently return no CodeFixers. However, they will soon be supported and as such comments have been left to indicate the error and fix they will accomplish.
+
+ [Fact]
+ public async Task CodeFix_IL2067_MismatchParamTargetsParam_PublicMethods ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+
+ private static void NeedsPublicMethodsOnParameter(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type parameter)
+ {
+ }
+
+ private static void M(Type type)
+ {
+ NeedsPublicMethodsOnParameter(type);
+ }
+ }
+ """;
+ // var fixtest = $$"""
+ //using System;
+ //using System.Diagnostics.CodeAnalysis;
+
+ //public class Foo
+ //{
+ //}
+
+ //class C
+ //{
+ //public static void Main()
+ //{
+ // M(typeof(Foo));
+ //}
+
+ //private static void NeedsPublicMethodsOnParameter(
+ // [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type parameter)
+ //{
+ //}
+
+ //private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ //{
+ // NeedsPublicMethodsOnParameter(type);
+ //}
+ //}
+ //""";
+ // await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new [] {
+ // // /0/Test0.cs(22,3): warning IL2067: 'parameter' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'C.NeedsPublicMethodsOnParameter(Type)'.
+ // // The parameter 'type' of method 'C.M(Type)' 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.
+ // VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter).WithSpan(22, 3, 22, 38).WithArguments("parameter", "C.NeedsPublicMethodsOnParameter(Type)", "type", "C.M(Type)", "'DynamicallyAccessedMemberTypes.PublicMethods'")},
+ // fixedExpected: Array.Empty<DiagnosticResult> ());
+ var diag = new[] {VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsParameter)
+ .WithSpan(22, 3, 22, 38)
+ .WithArguments("parameter",
+ "C.NeedsPublicMethodsOnParameter(Type)",
+ "type", "C.M(Type)",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'")};
+ await VerifyDynamicallyAccessedMembersCodeFix (test, test, diag, diag);
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2092_MismatchMethodParamBtOverride_NonPublicMethods ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ public class Base
+ {
+ public virtual void M([DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods)] Type t) {}
+ }
+
+ public class C : Base
+ {
+ public override void M(Type t) {}
+
+ public static void Main() {
+
+ }
+ }
+ """;
+ // var fixtest = $$"""
+ //using System;
+ //using System.Diagnostics.CodeAnalysis;
+
+ //public class Base
+ //{
+ // public virtual void M([DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods)] Type t) {}
+ //}
+
+ //public class C : Base
+ //{
+ // public override void M([DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods)] Type t) {}
+
+ // public static void Main() {
+
+ //}
+ //}
+ //""";
+ // await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new [] {
+ // // /0/Test0.cs(11,33): warning IL2092: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter 't' of method 'C.M(Type)'
+ // // don't match overridden parameter 't' of method 'Base.M(Type)'.
+ // // All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.
+ // VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides)
+ // .WithSpan(11, 30, 11, 31)
+ // .WithArguments("t", "C.M(Type)",
+ // "t",
+ // "Base.M(Type)") },
+ // fixedExpected: Array.Empty<DiagnosticResult> ());
+ var diag = new[] {VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides)
+ .WithSpan(11, 30, 11, 31)
+ .WithArguments("t", "C.M(Type)",
+ "t",
+ "Base.M(Type)") };
+ await VerifyDynamicallyAccessedMembersCodeFix (test, test, diag, diag);
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2092_MismatchMethodParamBtOverride_NonPublicMethods_Reverse ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ public class Base
+ {
+ public virtual void M(Type t) {}
+ }
+
+ public class C : Base
+ {
+ public override void M([DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods)] Type t) {}
+
+ public static void Main() {
+
+ }
+ }
+ """;
+ //var fixtest = $$"""
+ //using System;
+ //using System.Diagnostics.CodeAnalysis;
+
+ //public class Base
+ //{
+ // public virtual void M([DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods)] Type t) {}
+ //}
+
+ //public class C : Base
+ //{
+ // public override void M([DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods)] Type t) {}
+
+ // public static void Main() {
+
+ //}
+ //}
+ //""";
+ // await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new [] {
+ // // /0/Test0.cs(11,140): warning IL2092: 'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter 't' of method 'C.M(Type)'
+ // // don't match overridden parameter 't' of method 'Base.M(Type)'.
+ // // All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.
+ // VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides)
+ // .WithSpan(11, 140, 11, 141)
+ // .WithArguments("t", "C.M(Type)",
+ // "t",
+ // "Base.M(Type)") },
+ // fixedExpected: Array.Empty<DiagnosticResult> ());
+ var diag = new[] {VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides)
+ .WithSpan(11, 140, 11, 141)
+ .WithArguments("t", "C.M(Type)",
+ "t",
+ "Base.M(Type)") };
+ await VerifyDynamicallyAccessedMembersCodeFix (test, test, diag, diag);
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2069_MismatchParamTargetsField_PublicMethods ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ public static void Main()
+ {
+ M(typeof(Foo));
+ }
+
+ private static void M(Type type)
+ {
+ f = type;
+ }
+
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ private static Type f = typeof(Foo);
+ }
+ """;
+
+ //var fixtest = $$"""
+ //using System;
+ //using System.Diagnostics.CodeAnalysis;
+
+ //public class Foo
+ //{
+ //}
+
+ //class C
+ //{
+ // public static void Main()
+ // {
+ // M(typeof(Foo));
+ // }
+
+ // private static void M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
+ // {
+ // f = type;
+ // }
+
+ // [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ // private static Type f = typeof(Foo);
+ //}
+ //""";
+ // await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new [] {
+ // // /0/Test0.cs(17,3): warning IL2069: value stored in field 'C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ // // The parameter 'type' of method 'C.M(Type)' 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.
+ // VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField)
+ // .WithSpan(17, 3, 17, 11)
+ // .WithArguments("C.f",
+ // "type",
+ // "C.M(Type)",
+ // "'DynamicallyAccessedMemberTypes.PublicMethods'")},
+ // fixedExpected: Array.Empty<DiagnosticResult> ());
+ var diag = new[] {VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsField)
+ .WithSpan(17, 3, 17, 11)
+ .WithArguments("C.f",
+ "type",
+ "C.M(Type)",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'")};
+ await VerifyDynamicallyAccessedMembersCodeFix (test, test, diag, diag);
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2075_MethodReturnTargetsParam_PublicMethods ()
+ {
+ var test = $$"""
+ using System;
+
+ public class Foo
+ {
+ }
+
+ class C
+ {
+ public static void Main()
+ {
+ GetFoo().GetMethod("Bar");
+ }
+
+ private static Type GetFoo ()
+ {
+ return typeof (Foo);
+ }
+ }
+ """;
+ // var fixtest = $$"""
+ //using System;
+
+ //public class Foo
+ //{
+ //}
+
+ //class C
+ //{
+ // public static void Main()
+ // {
+ // GetFoo().GetMethod("Bar");
+ //}
+
+ // [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
+ //private static Type GetFoo ()
+ //{
+ // return typeof (Foo);
+ //}
+ //}
+ //""";
+ //await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new[] {
+ // // /0/Test0.cs(11,3): warning IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
+ // // The return value of method 'C.GetFoo()' 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.
+ // VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter)
+ // .WithSpan(11, 3, 11, 28)
+ // .WithArguments("System.Type.GetMethod(String)",
+ // "C.GetFoo()",
+ // "'DynamicallyAccessedMemberTypes.PublicMethods'")},
+ // fixedExpected: Array.Empty<DiagnosticResult> ());
+ var diag = new[] {VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter)
+ .WithSpan(11, 3, 11, 28)
+ .WithArguments("System.Type.GetMethod(String)",
+ "C.GetFoo()",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'")};
+ await VerifyDynamicallyAccessedMembersCodeFix (test, test, diag, diag);
+ }
+
+ [Fact]
+ public async Task CodeFix_IL2068_MismatchParamTargetsMethodReturn ()
+ {
+ var test = $$"""
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ class C
+ {
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ Type M(Type t) {
+ return t;
+ }
+ }
+ """;
+ // await VerifyDynamicallyAccessedMembersCodeFix (test, fixtest, new [] {
+ // // /0/Test0.cs(8,10): warning IL2068: 'C.M(Type)' method return value does not satisfy 'DynamicallyAccessedMemberTypes.All' requirements.
+ // // The parameter 't' of method 'C.M(Type)' 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.
+ // VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType)
+ // .WithSpan(8, 10, 8, 11)
+ // .WithArguments("C.M(Type)",
+ // "t",
+ // "C.M(Type)",
+ // "'DynamicallyAccessedMemberTypes.All'")},
+ // fixedExpected: Array.Empty<DiagnosticResult> ());
+ var diag = new[] {VerifyCS.Diagnostic(DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsMethodReturnType)
+ .WithSpan(8, 10, 8, 11)
+ .WithArguments("C.M(Type)",
+ "t",
+ "C.M(Type)",
+ "'DynamicallyAccessedMemberTypes.All'")};
+ await VerifyDynamicallyAccessedMembersCodeFix (test, test, diag, diag);
+ }
+ }
+} \ No newline at end of file