From ffeb6294267a9a46ccafd123c5e0ee1e35e7d93a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 2 Aug 2024 20:19:42 +0000 Subject: [PATCH 1/2] Don't store diagnostics in DiagnosticContext Instead, report them immediately. --- .../DynamicallyAccessedMembersAnalyzer.cs | 8 +--- .../TrimAnalysis/DiagnosticContext.cs | 11 ++--- .../FeatureCheckReturnValuePattern.cs | 13 +++--- .../TrimAnalysisAssignmentPattern.cs | 6 +-- .../TrimAnalysisFieldAccessPattern.cs | 9 ++--- ...TrimAnalysisGenericInstantiationPattern.cs | 8 ++-- .../TrimAnalysisMethodCallPattern.cs | 11 ++--- .../TrimAnalysis/TrimAnalysisPatternStore.cs | 40 +++++++------------ .../TrimAnalysisReflectionAccessPattern.cs | 9 ++--- .../TrimAnalysis/TrimDataFlowAnalysis.cs | 4 +- 10 files changed, 44 insertions(+), 75 deletions(-) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index c407ac62c4b25..8b40da0fb088b 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,13 @@ public override void Initialize (AnalysisContext context) return; var location = GetPrimaryLocation (type.Locations); - DiagnosticContext diagnosticContext = new (location); + DiagnosticContext diagnosticContext = new (location, context.ReportDiagnostic); if (type.BaseType is INamedTypeSymbol baseType) GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, baseType); foreach (var interfaceType in type.Interfaces) GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, interfaceType); - - foreach (var diagnostic in diagnosticContext.Diagnostics) - context.ReportDiagnostic (diagnostic); }, 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..850944ebe2527 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs @@ -12,13 +12,14 @@ namespace ILLink.Shared.TrimAnalysis { public readonly partial struct DiagnosticContext { - public List Diagnostics { get; } = new (); - readonly Location? Location { get; init; } - public DiagnosticContext (Location location) + readonly Action _reportDiagnostic; + + public DiagnosticContext (Location location, Action reportDiagnostic) { Location = location; + _reportDiagnostic = reportDiagnostic; } public static DiagnosticContext CreateDisabled () => new () { Location = null }; @@ -33,7 +34,7 @@ public partial void AddDiagnostic (DiagnosticId id, params string[] args) if (Location == null) return; - Diagnostics.Add (CreateDiagnostic (id, args)); + _reportDiagnostic (CreateDiagnostic (id, args)); } public partial void AddDiagnostic (DiagnosticId id, ValueWithDynamicallyAccessedMembers actualValue, ValueWithDynamicallyAccessedMembers expectedAnnotationsValue, params string[] args) @@ -41,7 +42,7 @@ public partial void AddDiagnostic (DiagnosticId id, ValueWithDynamicallyAccessed if (Location == 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/TrimAnalysisAssignmentPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs index 3517ee4ddc5a2..3bb819b1be07b 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)) { @@ -71,8 +71,6 @@ public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext conte } } } - - 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..bc5beff9da982 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,9 +43,9 @@ 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 ()); + DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation (), reportDiagnostic); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { @@ -63,8 +63,6 @@ public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext conte 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..4e44403da57bb 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,9 +69,9 @@ 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 ()); + DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation (), reportDiagnostic); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) @@ -87,8 +84,6 @@ public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext conte 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..ed114da12c832 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,9 +43,9 @@ 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 ()); + DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation (), reportDiagnostic); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { @@ -55,8 +54,6 @@ public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext conte 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/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 ( From d42e9b7a43a9031e60c5cc3ec5596605f178823a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 2 Aug 2024 21:24:27 +0000 Subject: [PATCH 2/2] Avoid DiagnosticContext in ReflectionAccessAnalyzer ReflectionAccessAnalyzer will need to be able to produce diagnostics with differing locations for a single call to GetReflectionAccessDiagnostics, to support warnings for DynamicallyAccessedMembers on type. This matches ReflectionMarker in ILLink and ILC, where MarkTypeForDynamicallyAccessedMembers takes a MessageOrigin rather than a DiagnosticContext. --- .../DynamicallyAccessedMembersAnalyzer.cs | 5 +- .../TrimAnalysis/DiagnosticContext.cs | 14 ++-- .../TrimAnalysis/GenericArgumentDataFlow.cs | 31 ++++---- .../TrimAnalysis/HandleCallAction.cs | 28 +++---- .../TrimAnalysis/ReflectionAccessAnalyzer.cs | 73 +++++++++++-------- ...RequireDynamicallyAccessedMembersAction.cs | 2 +- .../TrimAnalysisAssignmentPattern.cs | 3 +- ...TrimAnalysisGenericInstantiationPattern.cs | 8 +- .../TrimAnalysisMethodCallPattern.cs | 5 +- .../TrimAnalysisReflectionAccessPattern.cs | 6 +- .../TrimAnalysis/TrimAnalysisVisitor.cs | 8 +- 11 files changed, 97 insertions(+), 86 deletions(-) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index 8b40da0fb088b..66b71ab4f9c38 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -116,13 +116,12 @@ public override void Initialize (AnalysisContext context) return; var location = GetPrimaryLocation (type.Locations); - DiagnosticContext diagnosticContext = new (location, context.ReportDiagnostic); 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); + 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 850944ebe2527..95874ad914b70 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/DiagnosticContext.cs @@ -12,26 +12,24 @@ namespace ILLink.Shared.TrimAnalysis { public readonly partial struct DiagnosticContext { - readonly Location? Location { get; init; } + public readonly Location Location { get; } - readonly Action _reportDiagnostic; + readonly Action? _reportDiagnostic; - public DiagnosticContext (Location location, Action reportDiagnostic) + 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; _reportDiagnostic (CreateDiagnostic (id, args)); @@ -39,7 +37,7 @@ public partial void AddDiagnostic (DiagnosticId id, params string[] args) public partial void AddDiagnostic (DiagnosticId id, ValueWithDynamicallyAccessedMembers actualValue, ValueWithDynamicallyAccessedMembers expectedAnnotationsValue, params string[] args) { - if (Location == null) + if (_reportDiagnostic is null) return; _reportDiagnostic (CreateDiagnostic (id, actualValue, expectedAnnotationsValue, args)); 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 3bb819b1be07b..46793d6b448c6 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs @@ -66,7 +66,8 @@ public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation (), reportDiagnostic); 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; } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs index 4e44403da57bb..707bffbd13358 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisMethodCallPattern.cs @@ -71,14 +71,15 @@ public TrimAnalysisMethodCallPattern Merge ( public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation (), reportDiagnostic); + 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)) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs index ed114da12c832..c432ccfecffc5 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisReflectionAccessPattern.cs @@ -45,13 +45,15 @@ public TrimAnalysisReflectionAccessPattern Merge ( public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation (), reportDiagnostic); + 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); } 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))