From d5af5bde0aa2918a8b1b94042be14a404fd5adf1 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 6 Aug 2024 09:32:50 -0700 Subject: [PATCH] Make ReflectionAccessAnalyzer logic more similar to ILLink/ILC (#105956) ReflectionAccessAnalyzer is analogous to ILLink/ILC's ReflectionMarker, and will be responsible for producing warnings about DynamicallyAccessedMembers on types when we fix https://github.com/dotnet/runtime/issues/102002. These warnings will not all have the same location since they can be reported on different members of the type. To support this, this is changing ReflectionAccessAnalyzer to create a DiagnosticContext as needed when reporting a warning, instead of taking it as an argument, which would require all warnings to share the same location (since DiagnosticContext holds a Location). This is similar to how ReflectionMarker takes a MessageOrigin instead of DiagnosticContext. --- .../DynamicallyAccessedMembersAnalyzer.cs | 11 +-- .../TrimAnalysis/DiagnosticContext.cs | 19 +++-- .../FeatureCheckReturnValuePattern.cs | 13 ++-- .../TrimAnalysis/GenericArgumentDataFlow.cs | 31 ++++---- .../TrimAnalysis/HandleCallAction.cs | 28 +++---- .../TrimAnalysis/ReflectionAccessAnalyzer.cs | 73 +++++++++++-------- ...RequireDynamicallyAccessedMembersAction.cs | 2 +- .../TrimAnalysisAssignmentPattern.cs | 9 +-- .../TrimAnalysisFieldAccessPattern.cs | 9 +-- ...TrimAnalysisGenericInstantiationPattern.cs | 14 ++-- .../TrimAnalysisMethodCallPattern.cs | 14 ++-- .../TrimAnalysis/TrimAnalysisPatternStore.cs | 40 ++++------ .../TrimAnalysisReflectionAccessPattern.cs | 13 ++-- .../TrimAnalysis/TrimAnalysisVisitor.cs | 8 +- .../TrimAnalysis/TrimDataFlowAnalysis.cs | 4 +- 15 files changed, 134 insertions(+), 154 deletions(-) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index c407ac62c4b25..66b71ab4f9c38 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -98,8 +98,7 @@ public override void Initialize (AnalysisContext context) foreach (var operationBlock in context.OperationBlocks) { TrimDataFlowAnalysis trimDataFlowAnalysis = new (context, dataFlowAnalyzerContext, operationBlock); trimDataFlowAnalysis.InterproceduralAnalyze (); - foreach (var diagnostic in trimDataFlowAnalysis.CollectDiagnostics ()) - context.ReportDiagnostic (diagnostic); + trimDataFlowAnalysis.ReportDiagnostics (context.ReportDiagnostic); } }); @@ -117,16 +116,12 @@ public override void Initialize (AnalysisContext context) return; var location = GetPrimaryLocation (type.Locations); - DiagnosticContext diagnosticContext = new (location); if (type.BaseType is INamedTypeSymbol baseType) - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, baseType); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, baseType, context.ReportDiagnostic); foreach (var interfaceType in type.Interfaces) - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, interfaceType); - - foreach (var diagnostic in diagnosticContext.Diagnostics) - context.ReportDiagnostic (diagnostic); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, interfaceType, context.ReportDiagnostic); }, SymbolKind.NamedType); context.RegisterSymbolAction (context => { VerifyMemberOnlyApplyToTypesOrStrings (context, context.Symbol); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs index b59ebf3749a51..95874ad914b70 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs @@ -12,36 +12,35 @@ namespace ILLink.Shared.TrimAnalysis { public readonly partial struct DiagnosticContext { - public List Diagnostics { get; } = new (); + public readonly Location Location { get; } - readonly Location? Location { get; init; } + readonly Action? _reportDiagnostic; - public DiagnosticContext (Location location) + public DiagnosticContext (Location location, Action? reportDiagnostic) { Location = location; + _reportDiagnostic = reportDiagnostic; } - public static DiagnosticContext CreateDisabled () => new () { Location = null }; - - public Diagnostic CreateDiagnostic (DiagnosticId id, params string[] args) + private Diagnostic CreateDiagnostic (DiagnosticId id, params string[] args) { return Diagnostic.Create (DiagnosticDescriptors.GetDiagnosticDescriptor (id), Location, args); } public partial void AddDiagnostic (DiagnosticId id, params string[] args) { - if (Location == null) + if (_reportDiagnostic is null) return; - Diagnostics.Add (CreateDiagnostic (id, args)); + _reportDiagnostic (CreateDiagnostic (id, args)); } public partial void AddDiagnostic (DiagnosticId id, ValueWithDynamicallyAccessedMembers actualValue, ValueWithDynamicallyAccessedMembers expectedAnnotationsValue, params string[] args) { - if (Location == null) + if (_reportDiagnostic is null) return; - Diagnostics.Add (CreateDiagnostic (id, actualValue, expectedAnnotationsValue, args)); + _reportDiagnostic (CreateDiagnostic (id, actualValue, expectedAnnotationsValue, args)); } private Diagnostic CreateDiagnostic (DiagnosticId id, ValueWithDynamicallyAccessedMembers actualValue, ValueWithDynamicallyAccessedMembers expectedAnnotationsValue, params string[] args) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FeatureCheckReturnValuePattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FeatureCheckReturnValuePattern.cs index c9d9bd6bd218f..40b822f44c0e2 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FeatureCheckReturnValuePattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FeatureCheckReturnValuePattern.cs @@ -1,6 +1,7 @@ // 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.Generic; using ILLink.Shared; using ILLink.Shared.DataFlow; @@ -29,22 +30,22 @@ public FeatureCheckReturnValuePattern ( OwningSymbol = owningSymbol; } - public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - var diagnosticContext = new DiagnosticContext (Operation.Syntax.GetLocation ()); + var diagnosticContext = new DiagnosticContext (Operation.Syntax.GetLocation (), reportDiagnostic); // For now, feature check validation is enabled only when trim analysis is enabled. if (!context.EnableTrimAnalyzer) - return diagnosticContext.Diagnostics; + return; if (!OwningSymbol.IsStatic || OwningSymbol.Type.SpecialType != SpecialType.System_Boolean || OwningSymbol.SetMethod != null) { // Warn about invalid feature checks (non-static or non-bool properties or properties with setter) diagnosticContext.AddDiagnostic ( DiagnosticId.InvalidFeatureGuard); - return diagnosticContext.Diagnostics; + return; } if (ReturnValue == FeatureChecksValue.All) - return diagnosticContext.Diagnostics; + return; ValueSet returnValueFeatures = ReturnValue.EnabledFeatures; // For any analyzer-supported feature that this property is declared to guard, @@ -63,8 +64,6 @@ public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext conte } } } - - return diagnosticContext.Diagnostics; } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs index 6ef16f07a9c0b..8eac76a299339 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs @@ -2,55 +2,54 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; -using ILLink.Shared.TypeSystemProxy; namespace ILLink.RoslynAnalyzer.TrimAnalysis { internal static class GenericArgumentDataFlow { - public static void ProcessGenericArgumentDataFlow (DiagnosticContext diagnosticContext, INamedTypeSymbol type) + public static void ProcessGenericArgumentDataFlow (Location location, INamedTypeSymbol type, Action reportDiagnostic) { - ProcessGenericArgumentDataFlow (diagnosticContext, type.TypeArguments, type.TypeParameters); + ProcessGenericArgumentDataFlow (location, type.TypeArguments, type.TypeParameters, reportDiagnostic); } - public static void ProcessGenericArgumentDataFlow (DiagnosticContext diagnosticContext, IMethodSymbol method) + public static void ProcessGenericArgumentDataFlow (Location location, IMethodSymbol method, Action reportDiagnostic) { - ProcessGenericArgumentDataFlow (diagnosticContext, method.TypeArguments, method.TypeParameters); + ProcessGenericArgumentDataFlow (location, method.TypeArguments, method.TypeParameters, reportDiagnostic); - ProcessGenericArgumentDataFlow (diagnosticContext, method.ContainingType); + ProcessGenericArgumentDataFlow (location, method.ContainingType, reportDiagnostic); } - public static void ProcessGenericArgumentDataFlow (DiagnosticContext diagnosticContext, IFieldSymbol field) + public static void ProcessGenericArgumentDataFlow (Location location, IFieldSymbol field, Action reportDiagnostic) { - ProcessGenericArgumentDataFlow (diagnosticContext, field.ContainingType); + ProcessGenericArgumentDataFlow (location, field.ContainingType, reportDiagnostic); } static void ProcessGenericArgumentDataFlow ( - DiagnosticContext diagnosticContext, + Location location, ImmutableArray typeArguments, - ImmutableArray typeParameters) + ImmutableArray typeParameters, + Action reportDiagnostic) { + var diagnosticContext = new DiagnosticContext (location, reportDiagnostic); for (int i = 0; i < typeArguments.Length; i++) { var typeArgument = typeArguments[i]; // Apply annotations to the generic argument var genericParameterValue = new GenericParameterValue (typeParameters[i]); if (genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { SingleValue genericArgumentValue = SingleValueExtensions.FromTypeSymbol (typeArgument)!; - var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, default (ReflectionAccessAnalyzer)); + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic); + var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, reflectionAccessAnalyzer); requireDynamicallyAccessedMembersAction.Invoke (genericArgumentValue, genericParameterValue); } // Recursively process generic argument data flow on the generic argument if it itself is generic - if (typeArgument is INamedTypeSymbol namedTypeArgument && namedTypeArgument.IsGenericType) { - ProcessGenericArgumentDataFlow (diagnosticContext, namedTypeArgument); - } + if (typeArgument is INamedTypeSymbol namedTypeArgument && namedTypeArgument.IsGenericType) + ProcessGenericArgumentDataFlow (location, namedTypeArgument, reportDiagnostic); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs index 911e67f5584a6..3e8d00d5d050f 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs @@ -1,6 +1,7 @@ // 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.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -27,18 +28,19 @@ internal partial struct HandleCallAction ValueSetLattice _multiValueLattice; public HandleCallAction ( - in DiagnosticContext diagnosticContext, + Location location, ISymbol owningSymbol, IOperation operation, - ValueSetLattice multiValueLattice) + ValueSetLattice multiValueLattice, + Action? reportDiagnostic) { _owningSymbol = owningSymbol; _operation = operation; _isNewObj = operation.Kind == OperationKind.ObjectCreation; - _diagnosticContext = diagnosticContext; + _diagnosticContext = new DiagnosticContext (location, reportDiagnostic); _annotations = FlowAnnotations.Instance; - _reflectionAccessAnalyzer = default; - _requireDynamicallyAccessedMembersAction = new (diagnosticContext, _reflectionAccessAnalyzer); + _reflectionAccessAnalyzer = new (reportDiagnostic); + _requireDynamicallyAccessedMembersAction = new (_diagnosticContext, _reflectionAccessAnalyzer); _multiValueLattice = multiValueLattice; } @@ -201,25 +203,25 @@ private partial bool TryResolveTypeNameForCreateInstanceAndMark (in MethodProxy } private partial void MarkStaticConstructor (TypeProxy type) - => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForConstructorsOnType (_diagnosticContext, type.Type, BindingFlags.Static, parameterCount: 0); + => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForConstructorsOnType (_diagnosticContext.Location, type.Type, BindingFlags.Static, parameterCount: 0); private partial void MarkEventsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags) - => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForEventsOnTypeHierarchy (_diagnosticContext, type.Type, name, bindingFlags); + => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForEventsOnTypeHierarchy (_diagnosticContext.Location, type.Type, name, bindingFlags); private partial void MarkFieldsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags) - => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForFieldsOnTypeHierarchy (_diagnosticContext, type.Type, name, bindingFlags); + => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForFieldsOnTypeHierarchy (_diagnosticContext.Location, type.Type, name, bindingFlags); private partial void MarkPropertiesOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags) - => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForPropertiesOnTypeHierarchy (_diagnosticContext, type.Type, name, bindingFlags); + => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForPropertiesOnTypeHierarchy (_diagnosticContext.Location, type.Type, name, bindingFlags); private partial void MarkPublicParameterlessConstructorOnType (TypeProxy type) - => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForPublicParameterlessConstructor (_diagnosticContext, type.Type); + => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForPublicParameterlessConstructor (_diagnosticContext.Location, type.Type); private partial void MarkConstructorsOnType (TypeProxy type, BindingFlags? bindingFlags, int? parameterCount) - => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForConstructorsOnType (_diagnosticContext, type.Type, bindingFlags, parameterCount); + => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForConstructorsOnType (_diagnosticContext.Location, type.Type, bindingFlags, parameterCount); private partial void MarkMethod (MethodProxy method) - => ReflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForMethod (_diagnosticContext, method.Method); + => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForMethod (_diagnosticContext.Location, method.Method); // TODO: Does the analyzer need to do something here? private partial void MarkType (TypeProxy type) { } @@ -229,7 +231,7 @@ private partial bool MarkAssociatedProperty (MethodProxy method) if (method.Method.MethodKind == MethodKind.PropertyGet || method.Method.MethodKind == MethodKind.PropertySet) { var property = (IPropertySymbol) method.Method.AssociatedSymbol!; Debug.Assert (property != null); - ReflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForProperty (_diagnosticContext, property!); + _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForProperty (_diagnosticContext.Location, property!); return true; } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs index 6fd225bdbe31b..51d684816418d 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs @@ -1,6 +1,7 @@ // 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.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -13,84 +14,90 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis { readonly struct ReflectionAccessAnalyzer { + readonly Action? _reportDiagnostic; + + public ReflectionAccessAnalyzer (Action? reportDiagnostic) => _reportDiagnostic = reportDiagnostic; + #pragma warning disable CA1822 // Mark members as static - the other partial implementations might need to be instance methods - internal void GetReflectionAccessDiagnostics (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, DynamicallyAccessedMemberTypes requiredMemberTypes, bool declaredOnly = false) + internal void GetReflectionAccessDiagnostics (Location location, ITypeSymbol typeSymbol, DynamicallyAccessedMemberTypes requiredMemberTypes, bool declaredOnly = false) { typeSymbol = typeSymbol.OriginalDefinition; foreach (var member in typeSymbol.GetDynamicallyAccessedMembers (requiredMemberTypes, declaredOnly)) { switch (member) { case IMethodSymbol method: - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, method); + GetReflectionAccessDiagnosticsForMethod (location, method); break; case IFieldSymbol field: - GetDiagnosticsForField (diagnosticContext, field); + GetDiagnosticsForField (location, field); break; case IPropertySymbol property: - GetReflectionAccessDiagnosticsForProperty (diagnosticContext, property); + GetReflectionAccessDiagnosticsForProperty (location, property); break; /* Skip Type and InterfaceImplementation marking since doesnt seem relevant for diagnostic generation case ITypeSymbol nestedType: - MarkType (diagnosticContext, nestedType); + MarkType (location, nestedType); break; case InterfaceImplementation interfaceImplementation: - MarkInterfaceImplementation (analysisContext, interfaceImplementation, dependencyKind); + MarkInterfaceImplementation (location, interfaceImplementation, dependencyKind); break; */ case IEventSymbol @event: - GetDiagnosticsForEvent (diagnosticContext, @event); + GetDiagnosticsForEvent (location, @event); break; } } } - internal void GetReflectionAccessDiagnosticsForEventsOnTypeHierarchy (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags) + internal void GetReflectionAccessDiagnosticsForEventsOnTypeHierarchy (Location location, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags) { foreach (var @event in typeSymbol.GetEventsOnTypeHierarchy (e => e.Name == name, bindingFlags)) - GetDiagnosticsForEvent (diagnosticContext, @event); + GetDiagnosticsForEvent (location, @event); } - internal void GetReflectionAccessDiagnosticsForFieldsOnTypeHierarchy (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags) + internal void GetReflectionAccessDiagnosticsForFieldsOnTypeHierarchy (Location location, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags) { foreach (var field in typeSymbol.GetFieldsOnTypeHierarchy (f => f.Name == name, bindingFlags)) - GetDiagnosticsForField (diagnosticContext, field); + GetDiagnosticsForField (location, field); } - internal void GetReflectionAccessDiagnosticsForPropertiesOnTypeHierarchy (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags) + internal void GetReflectionAccessDiagnosticsForPropertiesOnTypeHierarchy (Location location, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags) { foreach (var prop in typeSymbol.GetPropertiesOnTypeHierarchy (p => p.Name == name, bindingFlags)) - GetReflectionAccessDiagnosticsForProperty (diagnosticContext, prop); + GetReflectionAccessDiagnosticsForProperty (location, prop); } - internal void GetReflectionAccessDiagnosticsForConstructorsOnType (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, BindingFlags? bindingFlags, int? parameterCount) + internal void GetReflectionAccessDiagnosticsForConstructorsOnType (Location location, ITypeSymbol typeSymbol, BindingFlags? bindingFlags, int? parameterCount) { foreach (var c in typeSymbol.GetConstructorsOnType (filter: parameterCount.HasValue ? c => c.Parameters.Length == parameterCount.Value : null, bindingFlags: bindingFlags)) - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, c); + GetReflectionAccessDiagnosticsForMethod (location, c); } - internal void GetReflectionAccessDiagnosticsForPublicParameterlessConstructor (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol) + internal void GetReflectionAccessDiagnosticsForPublicParameterlessConstructor (Location location, ITypeSymbol typeSymbol) { foreach (var c in typeSymbol.GetConstructorsOnType (filter: m => (m.DeclaredAccessibility == Accessibility.Public) && m.Parameters.Length == 0)) - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, c); + GetReflectionAccessDiagnosticsForMethod (location, c); } - static void ReportRequiresUnreferencedCodeDiagnostic (in DiagnosticContext diagnosticContext, AttributeData requiresAttributeData, ISymbol member) + void ReportRequiresUnreferencedCodeDiagnostic (Location location, AttributeData requiresAttributeData, ISymbol member) { var message = RequiresUnreferencedCodeUtils.GetMessageFromAttribute (requiresAttributeData); var url = RequiresAnalyzerBase.GetUrlFromAttribute (requiresAttributeData); + var diagnosticContext = new DiagnosticContext (location, _reportDiagnostic); diagnosticContext.AddDiagnostic (DiagnosticId.RequiresUnreferencedCode, member.GetDisplayName (), message, url); } - internal static void GetReflectionAccessDiagnosticsForMethod (in DiagnosticContext diagnosticContext, IMethodSymbol methodSymbol) + internal void GetReflectionAccessDiagnosticsForMethod (Location location, IMethodSymbol methodSymbol) { if (methodSymbol.IsInRequiresUnreferencedCodeAttributeScope (out var requiresUnreferencedCodeAttributeData)) { - ReportRequiresUnreferencedCodeDiagnostic (diagnosticContext, requiresUnreferencedCodeAttributeData, methodSymbol); + ReportRequiresUnreferencedCodeDiagnostic (location, requiresUnreferencedCodeAttributeData, methodSymbol); } else { - GetDiagnosticsForReflectionAccessToDAMOnMethod (diagnosticContext, methodSymbol); + GetDiagnosticsForReflectionAccessToDAMOnMethod (location, methodSymbol); } } - internal static void GetDiagnosticsForReflectionAccessToDAMOnMethod (DiagnosticContext diagnosticContext, IMethodSymbol methodSymbol) + internal void GetDiagnosticsForReflectionAccessToDAMOnMethod (Location location, IMethodSymbol methodSymbol) { + var diagnosticContext = new DiagnosticContext (location, _reportDiagnostic); if (methodSymbol.IsVirtual && FlowAnnotations.GetMethodReturnValueAnnotation (methodSymbol) != DynamicallyAccessedMemberTypes.None) { diagnosticContext.AddDiagnostic (DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection, methodSymbol.GetDisplayName ()); } else { @@ -103,31 +110,33 @@ internal static void GetDiagnosticsForReflectionAccessToDAMOnMethod (DiagnosticC } } - internal static void GetReflectionAccessDiagnosticsForProperty (in DiagnosticContext diagnosticContext, IPropertySymbol propertySymbol) + internal void GetReflectionAccessDiagnosticsForProperty (Location location, IPropertySymbol propertySymbol) { if (propertySymbol.SetMethod is not null) - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, propertySymbol.SetMethod); + GetReflectionAccessDiagnosticsForMethod (location, propertySymbol.SetMethod); if (propertySymbol.GetMethod is not null) - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, propertySymbol.GetMethod); + GetReflectionAccessDiagnosticsForMethod (location, propertySymbol.GetMethod); } - static void GetDiagnosticsForEvent (in DiagnosticContext diagnosticContext, IEventSymbol eventSymbol) + void GetDiagnosticsForEvent (Location location, IEventSymbol eventSymbol) { if (eventSymbol.AddMethod is not null) - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, eventSymbol.AddMethod); + GetReflectionAccessDiagnosticsForMethod (location, eventSymbol.AddMethod); if (eventSymbol.RemoveMethod is not null) - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, eventSymbol.RemoveMethod); + GetReflectionAccessDiagnosticsForMethod (location, eventSymbol.RemoveMethod); if (eventSymbol.RaiseMethod is not null) - GetReflectionAccessDiagnosticsForMethod (diagnosticContext, eventSymbol.RaiseMethod); + GetReflectionAccessDiagnosticsForMethod (location, eventSymbol.RaiseMethod); } - static void GetDiagnosticsForField (in DiagnosticContext diagnosticContext, IFieldSymbol fieldSymbol) + void GetDiagnosticsForField (Location location, IFieldSymbol fieldSymbol) { if (fieldSymbol.TryGetRequiresUnreferencedCodeAttribute (out var requiresUnreferencedCodeAttributeData)) - ReportRequiresUnreferencedCodeDiagnostic (diagnosticContext, requiresUnreferencedCodeAttributeData, fieldSymbol); + ReportRequiresUnreferencedCodeDiagnostic (location, requiresUnreferencedCodeAttributeData, fieldSymbol); - if (fieldSymbol.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None) + if (fieldSymbol.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None) { + var diagnosticContext = new DiagnosticContext (location, _reportDiagnostic); diagnosticContext.AddDiagnostic (DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection, fieldSymbol.GetDisplayName ()); + } } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs index 74735a7fa7470..5226aad4f0320 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs @@ -35,6 +35,6 @@ public partial bool TryResolveTypeNameAndMark (string typeName, bool needsAssemb } private partial void MarkTypeForDynamicallyAccessedMembers (in TypeProxy type, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) => - _reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (_diagnosticContext, type.Type, dynamicallyAccessedMemberTypes); + _reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (_diagnosticContext.Location, type.Type, dynamicallyAccessedMemberTypes); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs index 3517ee4ddc5a2..46793d6b448c6 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs @@ -53,9 +53,9 @@ public TrimAnalysisAssignmentPattern Merge ( featureContextLattice.Meet (FeatureContext, other.FeatureContext)); } - public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - var diagnosticContext = new DiagnosticContext (Operation.Syntax.GetLocation ()); + var diagnosticContext = new DiagnosticContext (Operation.Syntax.GetLocation (), reportDiagnostic); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { @@ -66,13 +66,12 @@ public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext conte if (targetValue is not ValueWithDynamicallyAccessedMembers targetWithDynamicallyAccessedMembers) throw new NotImplementedException (); - var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, default (ReflectionAccessAnalyzer)); + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic); + var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, reflectionAccessAnalyzer); requireDynamicallyAccessedMembersAction.Invoke (sourceValue, targetWithDynamicallyAccessedMembers); } } } - - return diagnosticContext.Diagnostics; } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisFieldAccessPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisFieldAccessPattern.cs index a9037e95d1a1c..f78e7c669706a 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisFieldAccessPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisFieldAccessPattern.cs @@ -1,9 +1,8 @@ // 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.Collections.Generic; +using System; using System.Diagnostics; -using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; using ILLink.RoslynAnalyzer.DataFlow; using Microsoft.CodeAnalysis; @@ -45,13 +44,11 @@ public TrimAnalysisFieldAccessPattern Merge ( featureContextLattice.Meet (FeatureContext, other.FeatureContext)); } - public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation ()); + DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation (), reportDiagnostic); foreach (var requiresAnalyzer in context.EnabledRequiresAnalyzers) requiresAnalyzer.CheckAndCreateRequiresDiagnostic (Operation, Field, OwningSymbol, context, FeatureContext, in diagnosticContext); - - return diagnosticContext.Diagnostics; } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisGenericInstantiationPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisGenericInstantiationPattern.cs index 82d48c54618f8..f0245634948c0 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisGenericInstantiationPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisGenericInstantiationPattern.cs @@ -1,7 +1,7 @@ // 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.Collections.Generic; +using System; using System.Diagnostics; using ILLink.RoslynAnalyzer.DataFlow; using ILLink.Shared.TrimAnalysis; @@ -43,28 +43,26 @@ public TrimAnalysisGenericInstantiationPattern Merge ( featureContextLattice.Meet (FeatureContext, other.FeatureContext)); } - public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation ()); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { + var location = Operation.Syntax.GetLocation (); switch (GenericInstantiation) { case INamedTypeSymbol type: - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, type); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, type, reportDiagnostic); break; case IMethodSymbol method: - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, method); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, method, reportDiagnostic); break; case IFieldSymbol field: - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, field); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, field, reportDiagnostic); break; } } - - return diagnosticContext.Diagnostics; } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs index 09fc7d80458e5..707bffbd13358 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs @@ -1,15 +1,12 @@ // 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.Collections.Generic; +using System; using System.Collections.Immutable; using System.Diagnostics; -using System.Runtime.InteropServices.ComTypes; using ILLink.RoslynAnalyzer.DataFlow; -using ILLink.Shared; using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; -using ILLink.Shared.TypeSystemProxy; using Microsoft.CodeAnalysis; using MultiValue = ILLink.Shared.DataFlow.ValueSet; @@ -72,23 +69,22 @@ public TrimAnalysisMethodCallPattern Merge ( featureContextLattice.Meet (FeatureContext, other.FeatureContext)); } - public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation ()); + var location = Operation.Syntax.GetLocation (); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { - TrimAnalysisVisitor.HandleCall(Operation, OwningSymbol, CalledMethod, Instance, Arguments, diagnosticContext, default, out var _); + TrimAnalysisVisitor.HandleCall(Operation, OwningSymbol, CalledMethod, Instance, Arguments, location, reportDiagnostic, default, out var _); } + var diagnosticContext = new DiagnosticContext (location, reportDiagnostic); foreach (var requiresAnalyzer in context.EnabledRequiresAnalyzers) { if (!requiresAnalyzer.IsIntrinsicallyHandled (CalledMethod, Instance, Arguments)) requiresAnalyzer.CheckAndCreateRequiresDiagnostic (Operation, CalledMethod, OwningSymbol, context, FeatureContext, in diagnosticContext); } - - return diagnosticContext.Diagnostics; } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs index 17f2e755f9083..8790a60b89d3f 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs @@ -1,12 +1,12 @@ // 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.Generic; using System.Diagnostics; using ILLink.RoslynAnalyzer.DataFlow; using ILLink.Shared.DataFlow; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; namespace ILLink.RoslynAnalyzer.TrimAnalysis { @@ -103,37 +103,25 @@ public void Add (FeatureCheckReturnValuePattern pattern) Debug.Assert (existingPattern == pattern, "Return values should be identical"); } - public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - foreach (var assignmentPattern in AssignmentPatterns.Values) { - foreach (var diagnostic in assignmentPattern.CollectDiagnostics (context)) - yield return diagnostic; - } + foreach (var assignmentPattern in AssignmentPatterns.Values) + assignmentPattern.ReportDiagnostics (context, reportDiagnostic); - foreach (var fieldAccessPattern in FieldAccessPatterns.Values) { - foreach (var diagnostic in fieldAccessPattern.CollectDiagnostics (context)) - yield return diagnostic; - } + foreach (var fieldAccessPattern in FieldAccessPatterns.Values) + fieldAccessPattern.ReportDiagnostics (context, reportDiagnostic); - foreach (var genericInstantiationPattern in GenericInstantiationPatterns.Values) { - foreach (var diagnostic in genericInstantiationPattern.CollectDiagnostics (context)) - yield return diagnostic; - } + foreach (var genericInstantiationPattern in GenericInstantiationPatterns.Values) + genericInstantiationPattern.ReportDiagnostics (context, reportDiagnostic); - foreach (var methodCallPattern in MethodCallPatterns.Values) { - foreach (var diagnostic in methodCallPattern.CollectDiagnostics (context)) - yield return diagnostic; - } + foreach (var methodCallPattern in MethodCallPatterns.Values) + methodCallPattern.ReportDiagnostics (context, reportDiagnostic); - foreach (var reflectionAccessPattern in ReflectionAccessPatterns.Values) { - foreach (var diagnostic in reflectionAccessPattern.CollectDiagnostics (context)) - yield return diagnostic; - } + foreach (var reflectionAccessPattern in ReflectionAccessPatterns.Values) + reflectionAccessPattern.ReportDiagnostics (context, reportDiagnostic); - foreach (var returnValuePattern in FeatureCheckReturnValuePatterns.Values) { - foreach (var diagnostic in returnValuePattern.CollectDiagnostics (context)) - yield return diagnostic; - } + foreach (var returnValuePattern in FeatureCheckReturnValuePatterns.Values) + returnValuePattern.ReportDiagnostics (context, reportDiagnostic); } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs index b599d79270d63..c432ccfecffc5 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs @@ -1,9 +1,8 @@ // 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.Collections.Generic; +using System; using System.Diagnostics; -using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; using ILLink.RoslynAnalyzer.DataFlow; using Microsoft.CodeAnalysis; @@ -44,19 +43,19 @@ public TrimAnalysisReflectionAccessPattern Merge ( featureContextLattice.Meet (FeatureContext, other.FeatureContext)); } - public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation ()); + var location = Operation.Syntax.GetLocation (); + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { - ReflectionAccessAnalyzer.GetDiagnosticsForReflectionAccessToDAMOnMethod (diagnosticContext, ReferencedMethod); + reflectionAccessAnalyzer.GetDiagnosticsForReflectionAccessToDAMOnMethod (location, ReferencedMethod); } + DiagnosticContext diagnosticContext = new (location, reportDiagnostic); foreach (var requiresAnalyzer in context.EnabledRequiresAnalyzers) requiresAnalyzer.CheckAndCreateRequiresDiagnostic (Operation, ReferencedMethod, OwningSymbol, context, FeatureContext, diagnosticContext); - - return diagnosticContext.Diagnostics; } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index b882a681bf89f..f28b5c67a1e85 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -293,8 +293,7 @@ public override MultiValue HandleMethodCall ( // Especially with DAM on type, this can lead to incorrectly analyzed code (as in unknown type which leads // to noise). ILLink has the same problem currently: https://github.com/dotnet/linker/issues/1952 - var diagnosticContext = DiagnosticContext.CreateDisabled (); - HandleCall (operation, OwningSymbol, calledMethod, instance, arguments, diagnosticContext, _multiValueLattice, out MultiValue methodReturnValue); + HandleCall (operation, OwningSymbol, calledMethod, instance, arguments, Location.None, null, _multiValueLattice, out MultiValue methodReturnValue); // This will copy the values if necessary TrimAnalysisPatterns.Add (new TrimAnalysisMethodCallPattern ( @@ -323,11 +322,12 @@ internal static void HandleCall( IMethodSymbol calledMethod, MultiValue instance, ImmutableArray arguments, - DiagnosticContext diagnosticContext, + Location location, + Action? reportDiagnostic, ValueSetLattice multiValueLattice, out MultiValue methodReturnValue) { - var handleCallAction = new HandleCallAction (diagnosticContext, owningSymbol, operation, multiValueLattice); + var handleCallAction = new HandleCallAction (location, owningSymbol, operation, multiValueLattice, reportDiagnostic); MethodProxy method = new (calledMethod); var intrinsicId = Intrinsics.GetIntrinsicIdForMethod (method); if (!handleCallAction.Invoke (method, instance, arguments, intrinsicId, out methodReturnValue)) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimDataFlowAnalysis.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimDataFlowAnalysis.cs index dd0865b12cd2e..3284176cb411b 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimDataFlowAnalysis.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimDataFlowAnalysis.cs @@ -52,9 +52,9 @@ public TrimDataFlowAnalysis ( _dataFlowAnalyzerContext = dataFlowAnalyzerContext; } - public IEnumerable CollectDiagnostics () + public void ReportDiagnostics (Action reportDiagnostic) { - return TrimAnalysisPatterns.CollectDiagnostics (_dataFlowAnalyzerContext); + TrimAnalysisPatterns.ReportDiagnostics (_dataFlowAnalyzerContext, reportDiagnostic); } protected override TrimAnalysisVisitor GetVisitor (