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:
authorJackson Schuster <36744439+jtschuster@users.noreply.github.com>2022-03-12 01:26:00 +0300
committerGitHub <noreply@github.com>2022-03-12 01:26:00 +0300
commitac6cfb356d9ec4a279511aa0bd667fd1143e9eb6 (patch)
treec5a2674d5963ab5c35b49c164e9ac3f5cfc56924
parent98c81d59e153a5bf4329470b9d0fbf6d58fdd6e8 (diff)
Warn on DAM mismatch between overrides (#2656)
* Warn on DAM mismatch between overrides
-rw-r--r--src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs81
-rw-r--r--src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs26
-rw-r--r--src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs12
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs2
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs42
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs68
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs11
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs12
8 files changed, 208 insertions, 46 deletions
diff --git a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
index fa7a8ca8a..bac91626c 100644
--- a/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
+++ b/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs
@@ -37,8 +37,12 @@ namespace ILLink.RoslynAnalyzer
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.UnrecognizedTypeInRuntimeHelpersRunClassConstructor));
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides));
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides));
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides));
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides));
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined));
-
return diagDescriptorsArrayBuilder.ToImmutable ();
void AddRange (DiagnosticId first, DiagnosticId last)
@@ -103,8 +107,13 @@ namespace ILLink.RoslynAnalyzer
}, SyntaxKind.GenericName);
context.RegisterSymbolAction (context => {
VerifyMemberOnlyApplyToTypesOrStrings (context, context.Symbol);
+ VerifyDamOnPropertyAndAccessorMatch (context, (IMethodSymbol) context.Symbol);
+ VerifyDamOnDerivedAndBaseMethodsMatch (context, (IMethodSymbol) context.Symbol);
}, SymbolKind.Method);
context.RegisterSymbolAction (context => {
+ VerifyDamOnInterfaceAndImplementationMethodsMatch (context, (INamedTypeSymbol) context.Symbol);
+ }, SymbolKind.NamedType);
+ context.RegisterSymbolAction (context => {
VerifyMemberOnlyApplyToTypesOrStrings (context, context.Symbol);
}, SymbolKind.Property);
context.RegisterSymbolAction (context => {
@@ -209,5 +218,75 @@ namespace ILLink.RoslynAnalyzer
context.ReportDiagnostic (Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnPropertyCanOnlyApplyToTypesOrStrings), member.Locations[0], member.GetDisplayName ()));
}
}
+
+ static void VerifyDamOnDerivedAndBaseMethodsMatch (SymbolAnalysisContext context, IMethodSymbol methodSymbol)
+ {
+ if (methodSymbol.TryGetOverriddenMember (out var overriddenSymbol) && overriddenSymbol is IMethodSymbol overriddenMethod
+ && context.Symbol is IMethodSymbol method) {
+ VerifyDamOnMethodsMatch (context, method, overriddenMethod);
+ }
+ }
+
+ static void VerifyDamOnMethodsMatch (SymbolAnalysisContext context, IMethodSymbol method, IMethodSymbol overriddenMethod)
+ {
+ if (FlowAnnotations.GetMethodReturnValueAnnotation (method) != FlowAnnotations.GetMethodReturnValueAnnotation (overriddenMethod))
+ context.ReportDiagnostic (Diagnostic.Create (
+ DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides),
+ 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]))
+ 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++) {
+ if (method.TypeParameters[i].GetDynamicallyAccessedMemberTypes () != overriddenMethod.TypeParameters[i].GetDynamicallyAccessedMemberTypes ())
+ context.ReportDiagnostic (Diagnostic.Create (
+ DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides),
+ method.TypeParameters[i].Locations[0],
+ method.TypeParameters[i].GetDisplayName (), method.GetDisplayName (),
+ overriddenMethod.TypeParameters[i].GetDisplayName (), overriddenMethod.GetDisplayName ()));
+ }
+
+ if (!method.IsStatic && method.GetDynamicallyAccessedMemberTypes () != overriddenMethod.GetDynamicallyAccessedMemberTypes ())
+ context.ReportDiagnostic (Diagnostic.Create (
+ DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnImplicitThisBetweenOverrides),
+ method.Locations[0],
+ method.GetDisplayName (), overriddenMethod.GetDisplayName ()));
+ }
+
+ static void VerifyDamOnInterfaceAndImplementationMethodsMatch (SymbolAnalysisContext context, INamedTypeSymbol type)
+ {
+ foreach (var (interfaceMember, implementationMember) in type.GetMemberInterfaceImplementationPairs ()) {
+ if (implementationMember is IMethodSymbol implementationMethod
+ && interfaceMember is IMethodSymbol interfaceMethod)
+ VerifyDamOnMethodsMatch (context, implementationMethod, interfaceMethod);
+ }
+ }
+
+ static void VerifyDamOnPropertyAndAccessorMatch (SymbolAnalysisContext context, IMethodSymbol methodSymbol)
+ {
+ if ((methodSymbol.MethodKind != MethodKind.PropertyGet && methodSymbol.MethodKind != MethodKind.PropertySet)
+ || (methodSymbol.AssociatedSymbol?.GetDynamicallyAccessedMemberTypes () == DynamicallyAccessedMemberTypes.None))
+ return;
+
+ // None on the return type of 'get' matches unannotated
+ if (methodSymbol.MethodKind == MethodKind.PropertyGet
+ && methodSymbol.GetDynamicallyAccessedMemberTypesOnReturnType () != DynamicallyAccessedMemberTypes.None
+ // None on parameter of 'set' matches unannotated
+ || methodSymbol.MethodKind == MethodKind.PropertySet
+ && methodSymbol.Parameters[0].GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None) {
+ context.ReportDiagnostic (Diagnostic.Create (
+ DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersConflictsBetweenPropertyAndAccessor),
+ methodSymbol.AssociatedSymbol!.Locations[0],
+ methodSymbol.AssociatedSymbol!.GetDisplayName (),
+ methodSymbol.GetDisplayName ()
+ ));
+ return;
+ }
+ }
}
}
diff --git a/src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs
index b15dfebb8..577e47c2d 100644
--- a/src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs
+++ b/src/ILLink.RoslynAnalyzer/INamedTypeSymbolExtensions.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Collections.Generic;
using Microsoft.CodeAnalysis;
namespace ILLink.RoslynAnalyzer
@@ -28,5 +29,30 @@ namespace ILLink.RoslynAnalyzer
return true;
}
+
+ internal static IEnumerable<(ISymbol InterfaceMember, ISymbol ImplementationMember)> GetMemberInterfaceImplementationPairs (this INamedTypeSymbol namedType)
+ {
+ var interfaces = namedType.Interfaces;
+ foreach (INamedTypeSymbol iface in interfaces) {
+ foreach (var pair in GetMatchingMembers (namedType, iface)) {
+ yield return pair;
+ }
+ }
+ }
+
+ private static IEnumerable<(ISymbol InterfaceMember, ISymbol ImplementationMember)> GetMatchingMembers (INamedTypeSymbol implementationSymbol, INamedTypeSymbol interfaceSymbol)
+ {
+ var members = interfaceSymbol.GetMembers ();
+ foreach (ISymbol interfaceMember in members) {
+ if (implementationSymbol.FindImplementationForInterfaceMember (interfaceMember) is ISymbol implementationMember) {
+ yield return (InterfaceMember: interfaceMember, ImplementationMember: implementationMember);
+ }
+ }
+ foreach (var iface in interfaceSymbol.Interfaces) {
+ foreach (var pair in GetMatchingMembers (implementationSymbol, iface)) {
+ yield return pair;
+ }
+ }
+ }
}
}
diff --git a/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs b/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs
index e659a10c1..23319e0fb 100644
--- a/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs
+++ b/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs
@@ -263,15 +263,9 @@ namespace ILLink.RoslynAnalyzer
SymbolAnalysisContext symbolAnalysisContext,
INamedTypeSymbol type)
{
- ImmutableArray<INamedTypeSymbol> interfaces = type.Interfaces;
- foreach (INamespaceOrTypeSymbol iface in interfaces) {
- var members = iface.GetMembers ();
- foreach (var member in members) {
- var implementation = type.FindImplementationForInterfaceMember (member);
- // In case the implementation is null because the user code is missing an implementation, we dont provide diagnostics.
- // The compiler will provide an error
- if (implementation != null && HasMismatchingAttributes (member, implementation))
- ReportMismatchInAttributesDiagnostic (symbolAnalysisContext, implementation, member, isInterface: true);
+ foreach (var memberpair in type.GetMemberInterfaceImplementationPairs ()) {
+ if (HasMismatchingAttributes (memberpair.InterfaceMember, memberpair.ImplementationMember)) {
+ ReportMismatchInAttributesDiagnostic (symbolAnalysisContext, memberpair.ImplementationMember, memberpair.InterfaceMember, isInterface: true);
}
}
}
diff --git a/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs b/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs
index 8ada1cff3..cd90ee2b7 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs
@@ -211,7 +211,7 @@ namespace ILLink.RoslynAnalyzer.Tests
return RunTest (allowMissingWarnings: true);
}
- [Fact (Skip = "https://github.com/dotnet/linker/issues/2273")]
+ [Fact]
public Task VirtualMethodHierarchyDataflowAnnotationValidation ()
{
return RunTest (nameof (VirtualMethodHierarchyDataflowAnnotationValidation));
diff --git a/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
index 9e250aabc..bd8723731 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
@@ -511,6 +511,7 @@ class C
using System.Globalization;
using System.Reflection;
+using System.Diagnostics.CodeAnalysis;
namespace System
{
@@ -534,6 +535,8 @@ namespace System
public override string Name => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors
+ | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
public override ConstructorInfo[] GetConstructors (BindingFlags bindingAttr)
{
throw new NotImplementedException ();
@@ -554,61 +557,76 @@ namespace System
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents
+ | DynamicallyAccessedMemberTypes.NonPublicEvents)]
public override EventInfo GetEvent (string name, BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
public override EventInfo[] GetEvents (BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
public override FieldInfo GetField (string name, BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields
+ | DynamicallyAccessedMemberTypes.NonPublicFields)]
public override FieldInfo[] GetFields (BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
+ [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
public override Type GetInterface (string name, bool ignoreCase)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
public override Type[] GetInterfaces ()
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)0x1FFF)]
public override MemberInfo[] GetMembers (BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
public override MethodInfo[] GetMethods (BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
public override Type GetNestedType (string name, BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
public override Type[] GetNestedTypes (BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
public override PropertyInfo[] GetProperties (BindingFlags bindingAttr)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public override object InvokeMember (string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
{
throw new NotImplementedException ();
@@ -624,16 +642,20 @@ namespace System
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors
+ | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
protected override ConstructorInfo GetConstructorImpl (BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
protected override MethodInfo GetMethodImpl (string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
{
throw new NotImplementedException ();
}
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
protected override PropertyInfo GetPropertyImpl (string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
{
throw new NotImplementedException ();
@@ -698,12 +720,12 @@ namespace System
}
}";
- // (178,16): warning IL2082: 'type' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.C.M2(Type)'.
+ // (200,16): 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 (178, 13, 178, 21)
+ .WithSpan (200, 13, 200, 21)
.WithArguments ("type", "System.C.M2(Type)", "System.C.M1()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
@@ -740,7 +762,7 @@ namespace System
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), ConversionOperation),
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter)
- .WithSpan (183, 13, 183, 37)
+ .WithSpan (205, 13, 205, 37)
.WithArguments ("type", "System.C.M2(Type)", "System.ConvertsToType.implicit operator Type(ConvertsToType)", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
@@ -780,7 +802,7 @@ namespace System
return VerifyDynamicallyAccessedMembersAnalyzer (string.Concat (GetSystemTypeBase (), AnnotatedConversionOperation),
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsParameter)
- .WithSpan (185, 13, 185, 37)
+ .WithSpan (207, 13, 207, 37)
.WithArguments ("type", "System.C.M2(Type)", "System.ConvertsToType.implicit operator Type(ConvertsToType)", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
@@ -843,12 +865,12 @@ namespace System
}
}";
- // (180,13): warning IL2083: 'System.C.M()' method return value does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ // (202,13): 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 (180, 20, 180, 24)
+ .WithSpan (202, 20, 202, 24)
.WithArguments ("System.C.M()", "System.C.M()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
@@ -876,12 +898,12 @@ namespace System
}
}";
- // (178,13): warning IL2084: value stored in field 'System.C.f' does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' requirements.
+ // (200,13): 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 (178, 13, 178, 21)
+ .WithSpan (200, 13, 200, 21)
.WithArguments ("System.C.f",
"System.C.M()",
"'DynamicallyAccessedMemberTypes.PublicMethods'"));
@@ -907,12 +929,12 @@ namespace System
}
}";
- // (178,13): warning IL2085: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethods()'.
+ // (200,13): 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 (178, 13, 178, 30)
+ .WithSpan (200, 13, 200, 30)
.WithArguments ("System.Type.GetMethods()", "System.C.M()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
#endregion
diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs
index 7be81d99e..e060c68ab 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -283,43 +284,68 @@ namespace ILLink.RoslynAnalyzer.Tests
private bool TryValidateLogContainsAttribute (AttributeSyntax attribute, List<Diagnostic> diagnostics, out int? matchIndex, out string? missingDiagnosticMessage)
{
- missingDiagnosticMessage = null;
- matchIndex = null;
+ if (!LogContains (attribute, diagnostics, out matchIndex, out string text)) {
+ missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{string.Join (Environment.NewLine, _diagnostics)}";
+ return false;
+ } else {
+ missingDiagnosticMessage = null;
+ return true;
+ }
+ }
+
+ private void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, IReadOnlyList<Diagnostic> diagnosticMessages)
+ {
var args = LinkerTestBase.GetAttributeArguments (attribute);
- var text = LinkerTestBase.GetStringFromExpression (args["#0"], _semanticModel);
+ var arg = args["#0"];
+ Assert.False (args.ContainsKey ("#1"));
+ _ = LinkerTestBase.GetStringFromExpression (arg, _semanticModel);
+ if (LogContains (attribute, diagnosticMessages, out var matchIndex, out var findText)) {
+ Assert.True (false, $"LogDoesNotContain failure: Text\n\"{findText}\"\nfound in diagnostic:\n {diagnosticMessages[(int) matchIndex]}");
+ }
+ }
+
+ private bool LogContains (AttributeSyntax attribute, IReadOnlyList<Diagnostic> diagnostics, [NotNullWhen (true)] out int? matchIndex, out string findText)
+ {
+
+ var args = LinkerTestBase.GetAttributeArguments (attribute);
+ findText = LinkerTestBase.GetStringFromExpression (args["#0"], _semanticModel);
// If the text starts with `warning IL...` then it probably follows the pattern
// 'warning <diagId>: <location>:'
// We don't want to repeat the location in the error message for the analyzer, so
// it's better to just trim here. We've already filtered by diagnostic location so
// the text location shouldn't matter
- if (text.StartsWith ("warning IL")) {
- var firstColon = text.IndexOf (": ");
+ if (findText.StartsWith ("warning IL")) {
+ var firstColon = findText.IndexOf (": ");
if (firstColon > 0) {
- var secondColon = text.IndexOf (": ", firstColon + 1);
+ var secondColon = findText.IndexOf (": ", firstColon + 1);
if (secondColon > 0) {
- text = text.Substring (secondColon + 2);
+ findText = findText.Substring (secondColon + 2);
}
}
}
- for (int i = 0; i < diagnostics.Count; i++) {
- if (diagnostics[i].GetMessage ().Contains (text)) {
- matchIndex = i;
- return true;
+ bool isRegex = args.TryGetValue ("regexMatch", out var regexMatchExpr)
+ && regexMatchExpr.GetLastToken ().Value is bool regexMatch
+ && regexMatch;
+ if (isRegex) {
+ var regex = new Regex (findText);
+ for (int i = 0; i < diagnostics.Count; i++) {
+ if (regex.IsMatch (diagnostics[i].GetMessage ())) {
+ matchIndex = i;
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0; i < diagnostics.Count; i++) {
+ if (diagnostics[i].GetMessage ().Contains (findText)) {
+ matchIndex = i;
+ return true;
+ }
}
}
-
- missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{string.Join (Environment.NewLine, _diagnostics)}";
+ matchIndex = null;
return false;
}
-
- private void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, IReadOnlyList<Diagnostic> diagnosticMessages)
- {
- var arg = Assert.Single (LinkerTestBase.GetAttributeArguments (attribute));
- var text = LinkerTestBase.GetStringFromExpression (arg.Value, _semanticModel);
- foreach (var diagnostic in diagnosticMessages)
- Assert.DoesNotContain (text, diagnostic.GetMessage ());
- }
}
}
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs
index 9506cf0db..e8aa8a654 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs
@@ -68,16 +68,27 @@ namespace Mono.Linker.Tests.Cases.DataFlow
class MyReflect : IReflect
{
public Type UnderlyingSystemType => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
public FieldInfo GetField (string name, BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
public FieldInfo[] GetFields (BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers ((DynamicallyAccessedMemberTypes) 8191)]
public MemberInfo[] GetMember (string name, BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers ((DynamicallyAccessedMemberTypes) 8191)]
public MemberInfo[] GetMembers (BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
public MethodInfo GetMethod (string name, BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
public MethodInfo GetMethod (string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
public MethodInfo[] GetMethods (BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
public PropertyInfo[] GetProperties (BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
public PropertyInfo GetProperty (string name, BindingFlags bindingAttr) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
public PropertyInfo GetProperty (string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException ();
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
public object InvokeMember (string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) => throw new NotImplementedException ();
}
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs
index ed83c7bea..8ff523a92 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/PropertyDataFlow.cs
@@ -292,15 +292,17 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[CompilerGenerated]
Type PropertyWithExistingAttributes_Field;
+ [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set", ProducedBy = ProducedBy.Analyzer)]
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
Type PropertyWithExistingAttributes {
- // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273
+ // On property/accessor mismatch, linker warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654
[ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.get",
ProducedBy = ProducedBy.Trimmer)]
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
get { return PropertyWithExistingAttributes_Field; }
- // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273
+ // On property/accessor mismatch, linker warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654
[ExpectedWarning ("IL2043", "PropertyWithExistingAttributes", "PropertyWithExistingAttributes.set",
ProducedBy = ProducedBy.Trimmer)]
[param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
@@ -328,15 +330,17 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[CompilerGenerated]
Type PropertyWithConflictingAttributes_Field;
+ [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.get", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.set", ProducedBy = ProducedBy.Analyzer)]
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
Type PropertyWithConflictingAttributes {
- // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273
+ // On property/accessor mismatch, linker warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654
[ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.get",
ProducedBy = ProducedBy.Trimmer)]
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)]
get { return PropertyWithConflictingAttributes_Field; }
- // Analyzer doesn't try to detect backing fields of properties: https://github.com/dotnet/linker/issues/2273
+ // On property/accessor mismatch, linker warns on accessor and analyzer warns on property https://github.com/dotnet/linker/issues/2654
[ExpectedWarning ("IL2043", "PropertyWithConflictingAttributes", "PropertyWithConflictingAttributes.set",
ProducedBy = ProducedBy.Trimmer)]
[param: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicConstructors)]