提交 ea61a2da 编写于 作者: S Sam Harwell

Simplify CreateWithLocationTags API

上级 d3551026
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle;
...@@ -11,7 +10,6 @@ ...@@ -11,7 +10,6 @@
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess namespace Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess
{ {
...@@ -173,9 +171,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) ...@@ -173,9 +171,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
Descriptor, Descriptor,
fadeLocation, fadeLocation,
ReportDiagnostic.Default, ReportDiagnostic.Default,
additionalLocations.Add(fadeLocation), additionalLocations,
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty additionalUnnecessaryLocations: ImmutableArray.Create(fadeLocation),
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), SpecializedCollections.SingletonEnumerable(additionalLocations.Length)),
properties)); properties));
// Put a diagnostic with the appropriate severity on the expression-statement itself. // Put a diagnostic with the appropriate severity on the expression-statement itself.
...@@ -193,9 +190,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) ...@@ -193,9 +190,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
Descriptor, Descriptor,
fadeLocation, fadeLocation,
ReportDiagnostic.Default, ReportDiagnostic.Default,
additionalLocations.Add(fadeLocation), additionalLocations,
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty additionalUnnecessaryLocations: ImmutableArray.Create(fadeLocation),
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), SpecializedCollections.SingletonEnumerable(additionalLocations.Length)),
properties)); properties));
} }
} }
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
...@@ -114,14 +113,16 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context) ...@@ -114,14 +113,16 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
// 'additionalLocations' is how we always pass along the locaiton of the first unreachable // 'additionalLocations' is how we always pass along the locaiton of the first unreachable
// statement in this group. // statement in this group.
var additionalLocations = SpecializedCollections.SingletonEnumerable(firstStatementLocation); var additionalLocations = ImmutableArray.Create(firstStatementLocation);
if (fadeOutCode) if (fadeOutCode)
{ {
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 }); Descriptor,
context.ReportDiagnostic( firstStatementLocation,
DiagnosticHelper.CreateWithLocationTags(Descriptor, firstStatementLocation, ReportDiagnostic.Default, additionalLocations, tagIndices)); ReportDiagnostic.Default,
additionalLocations: ImmutableArray<Location>.Empty,
additionalUnnecessaryLocations: additionalLocations));
} }
else else
{ {
...@@ -134,22 +135,18 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context) ...@@ -134,22 +135,18 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
{ {
var span = TextSpan.FromBounds(section[0].FullSpan.Start, section.Last().FullSpan.End); var span = TextSpan.FromBounds(section[0].FullSpan.Start, section.Last().FullSpan.End);
var location = root.SyntaxTree.GetLocation(span); var location = root.SyntaxTree.GetLocation(span);
var additionalUnnecessaryLocations = ImmutableArray<Location>.Empty;
// Mark subsequent sections as being 'cascaded'. We don't need to actually process them // Mark subsequent sections as being 'cascaded'. We don't need to actually process them
// when doing a fix-all as they'll be scooped up when we process the fix for the first // when doing a fix-all as they'll be scooped up when we process the fix for the first
// section. // section.
if (fadeOutCode) if (fadeOutCode)
{ {
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty additionalUnnecessaryLocations = ImmutableArray.Create(location);
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { additionalLocations.Count() });
context.ReportDiagnostic(
DiagnosticHelper.CreateWithLocationTags(Descriptor, location, ReportDiagnostic.Default, additionalLocations.Concat(location), tagIndices, s_subsequentSectionProperties));
} }
else
{
context.ReportDiagnostic( context.ReportDiagnostic(
Diagnostic.Create(Descriptor, location, additionalLocations, s_subsequentSectionProperties)); DiagnosticHelper.CreateWithLocationTags(Descriptor, location, ReportDiagnostic.Default, additionalLocations, additionalUnnecessaryLocations, s_subsequentSectionProperties));
}
} }
} }
} }
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle;
...@@ -52,9 +51,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) ...@@ -52,9 +51,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
Descriptor, Descriptor,
defaultExpression.GetLocation(), defaultExpression.GetLocation(),
preference.Notification.Severity, preference.Notification.Severity,
additionalLocations: new[] { defaultExpression.SyntaxTree.GetLocation(fadeSpan) }, additionalLocations: ImmutableArray<Location>.Empty,
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty additionalUnnecessaryLocations: ImmutableArray.Create(defaultExpression.SyntaxTree.GetLocation(fadeSpan))));
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 })));
} }
} }
} }
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#nullable enable #nullable enable
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Threading; using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
...@@ -61,9 +60,8 @@ private void ReportDiagnosticsIfNeeded(NameColonSyntax nameColon, SyntaxNodeAnal ...@@ -61,9 +60,8 @@ private void ReportDiagnosticsIfNeeded(NameColonSyntax nameColon, SyntaxNodeAnal
Descriptor, Descriptor,
nameColon.GetLocation(), nameColon.GetLocation(),
preference.Notification.Severity, preference.Notification.Severity,
additionalLocations: new[] { syntaxTree.GetLocation(fadeSpan) }, additionalLocations: ImmutableArray<Location>.Empty,
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty additionalUnnecessaryLocations: ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))));
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 })));
} }
private void ReportDiagnosticsIfNeeded(NameEqualsSyntax nameEquals, SyntaxNodeAnalysisContext context, AnalyzerOptions options, SyntaxTree syntaxTree, CancellationToken cancellationToken) private void ReportDiagnosticsIfNeeded(NameEqualsSyntax nameEquals, SyntaxNodeAnalysisContext context, AnalyzerOptions options, SyntaxTree syntaxTree, CancellationToken cancellationToken)
...@@ -89,9 +87,8 @@ private void ReportDiagnosticsIfNeeded(NameEqualsSyntax nameEquals, SyntaxNodeAn ...@@ -89,9 +87,8 @@ private void ReportDiagnosticsIfNeeded(NameEqualsSyntax nameEquals, SyntaxNodeAn
Descriptor, Descriptor,
nameEquals.GetLocation(), nameEquals.GetLocation(),
preference.Notification.Severity, preference.Notification.Severity,
additionalLocations: new[] { syntaxTree.GetLocation(fadeSpan) }, additionalLocations: ImmutableArray<Location>.Empty,
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty additionalUnnecessaryLocations: ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))));
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 0 })));
} }
} }
} }
...@@ -33,7 +33,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod ...@@ -33,7 +33,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor. /// Message for the diagnostic descriptor.
/// <see langword="null"/> if the message is identical to the title. /// <see langword="null"/> if the message is identical to the title.
/// </param> /// </param>
/// <param name="isUnnecessary"></param> /// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param> /// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer( protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId, string diagnosticId,
...@@ -62,7 +62,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod ...@@ -62,7 +62,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor. /// Message for the diagnostic descriptor.
/// <see langword="null"/> if the message is identical to the title. /// <see langword="null"/> if the message is identical to the title.
/// </param> /// </param>
/// <param name="isUnnecessary"></param> /// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param> /// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer( protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId, string diagnosticId,
...@@ -90,7 +90,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod ...@@ -90,7 +90,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor. /// Message for the diagnostic descriptor.
/// Null if the message is identical to the title. /// Null if the message is identical to the title.
/// </param> /// </param>
/// <param name="isUnnecessary"></param> /// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param> /// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer( protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId, string diagnosticId,
...@@ -120,7 +120,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod ...@@ -120,7 +120,7 @@ internal abstract class AbstractBuiltInCodeStyleDiagnosticAnalyzer : AbstractCod
/// Message for the diagnostic descriptor. /// Message for the diagnostic descriptor.
/// Null if the message is identical to the title. /// Null if the message is identical to the title.
/// </param> /// </param>
/// <param name="isUnnecessary"></param> /// <param name="isUnnecessary"><see langword="true"/> if the diagnostic is reported on unnecessary code; otherwise, <see langword="false"/>.</param>
/// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param> /// <param name="configurable">Flag indicating if the reported diagnostics are configurable by the end users</param>
protected AbstractBuiltInCodeStyleDiagnosticAnalyzer( protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(
string diagnosticId, string diagnosticId,
......
...@@ -69,11 +69,13 @@ internal static class DiagnosticHelper ...@@ -69,11 +69,13 @@ internal static class DiagnosticHelper
/// <param name="additionalLocations"> /// <param name="additionalLocations">
/// An optional set of additional locations related to the diagnostic. /// An optional set of additional locations related to the diagnostic.
/// Typically, these are locations of other items referenced in the message. /// Typically, these are locations of other items referenced in the message.
/// If null, <see cref="Diagnostic.AdditionalLocations"/> will return an empty list. /// These locations are joined with <paramref name="additionalUnnecessaryLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param> /// </param>
/// <param name="tagIndices"> /// <param name="additionalUnnecessaryLocations">
/// a map of location tag to index in additional locations. /// An optional set of additional locations indicating unnecessary code related to the diagnostic.
/// "AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer" for an example of usage. /// These locations are joined with <paramref name="additionalLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param> /// </param>
/// <param name="messageArgs">Arguments to the message of the diagnostic.</param> /// <param name="messageArgs">Arguments to the message of the diagnostic.</param>
/// <returns>The <see cref="Diagnostic"/> instance.</returns> /// <returns>The <see cref="Diagnostic"/> instance.</returns>
...@@ -81,11 +83,74 @@ internal static class DiagnosticHelper ...@@ -81,11 +83,74 @@ internal static class DiagnosticHelper
DiagnosticDescriptor descriptor, DiagnosticDescriptor descriptor,
Location location, Location location,
ReportDiagnostic effectiveSeverity, ReportDiagnostic effectiveSeverity,
IEnumerable<Location> additionalLocations, ImmutableArray<Location> additionalLocations,
IDictionary<string, IEnumerable<int>> tagIndices, ImmutableArray<Location> additionalUnnecessaryLocations,
params object[] messageArgs) params object[] messageArgs)
{ {
return CreateWithLocationTags(descriptor, location, effectiveSeverity, additionalLocations, tagIndices, ImmutableDictionary<string, string>.Empty, messageArgs); if (additionalUnnecessaryLocations.IsEmpty)
{
return Create(descriptor, location, effectiveSeverity, additionalLocations, ImmutableDictionary<string, string>.Empty, messageArgs);
}
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(WellKnownDiagnosticTags.Unnecessary, Enumerable.Range(additionalLocations.Length, additionalUnnecessaryLocations.Length));
return CreateWithLocationTags(
descriptor,
location,
effectiveSeverity,
additionalLocations.AddRange(additionalUnnecessaryLocations),
tagIndices,
ImmutableDictionary<string, string>.Empty,
messageArgs);
}
/// <summary>
/// Create a diagnostic that adds properties specifying a tag for a set of locations.
/// </summary>
/// <param name="descriptor">A <see cref="DiagnosticDescriptor"/> describing the diagnostic.</param>
/// <param name="location">An optional primary location of the diagnostic. If null, <see cref="Location"/> will return <see cref="Location.None"/>.</param>
/// <param name="effectiveSeverity">Effective severity of the diagnostic.</param>
/// <param name="additionalLocations">
/// An optional set of additional locations related to the diagnostic.
/// Typically, these are locations of other items referenced in the message.
/// These locations are joined with <paramref name="additionalUnnecessaryLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param>
/// <param name="additionalUnnecessaryLocations">
/// An optional set of additional locations indicating unnecessary code related to the diagnostic.
/// These locations are joined with <paramref name="additionalLocations"/> to produce the value for
/// <see cref="Diagnostic.AdditionalLocations"/>.
/// </param>
/// <param name="properties">
/// An optional set of name-value pairs by means of which the analyzer that creates the diagnostic
/// can convey more detailed information to the fixer.
/// </param>
/// <param name="messageArgs">Arguments to the message of the diagnostic.</param>
/// <returns>The <see cref="Diagnostic"/> instance.</returns>
public static Diagnostic CreateWithLocationTags(
DiagnosticDescriptor descriptor,
Location location,
ReportDiagnostic effectiveSeverity,
ImmutableArray<Location> additionalLocations,
ImmutableArray<Location> additionalUnnecessaryLocations,
ImmutableDictionary<string, string> properties,
params object[] messageArgs)
{
if (additionalUnnecessaryLocations.IsEmpty)
{
return Create(descriptor, location, effectiveSeverity, additionalLocations, ImmutableDictionary<string, string>.Empty, messageArgs);
}
var tagIndices = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(WellKnownDiagnosticTags.Unnecessary, Enumerable.Range(additionalLocations.Length, additionalUnnecessaryLocations.Length));
return CreateWithLocationTags(
descriptor,
location,
effectiveSeverity,
additionalLocations.AddRange(additionalUnnecessaryLocations),
tagIndices,
properties,
messageArgs);
} }
/// <summary> /// <summary>
...@@ -97,7 +162,6 @@ internal static class DiagnosticHelper ...@@ -97,7 +162,6 @@ internal static class DiagnosticHelper
/// <param name="additionalLocations"> /// <param name="additionalLocations">
/// An optional set of additional locations related to the diagnostic. /// An optional set of additional locations related to the diagnostic.
/// Typically, these are locations of other items referenced in the message. /// Typically, these are locations of other items referenced in the message.
/// If null, <see cref="Diagnostic.AdditionalLocations"/> will return an empty list.
/// </param> /// </param>
/// <param name="tagIndices"> /// <param name="tagIndices">
/// a map of location tag to index in additional locations. /// a map of location tag to index in additional locations.
...@@ -109,7 +173,7 @@ internal static class DiagnosticHelper ...@@ -109,7 +173,7 @@ internal static class DiagnosticHelper
/// </param> /// </param>
/// <param name="messageArgs">Arguments to the message of the diagnostic.</param> /// <param name="messageArgs">Arguments to the message of the diagnostic.</param>
/// <returns>The <see cref="Diagnostic"/> instance.</returns> /// <returns>The <see cref="Diagnostic"/> instance.</returns>
public static Diagnostic CreateWithLocationTags( private static Diagnostic CreateWithLocationTags(
DiagnosticDescriptor descriptor, DiagnosticDescriptor descriptor,
Location location, Location location,
ReportDiagnostic effectiveSeverity, ReportDiagnostic effectiveSeverity,
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#nullable enable #nullable enable
using System; using System;
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
...@@ -34,12 +33,6 @@ internal abstract class AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer< ...@@ -34,12 +33,6 @@ internal abstract class AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer<
new LocalizableResourceString(nameof(AnalyzersResources.Parentheses_can_be_removed), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)), new LocalizableResourceString(nameof(AnalyzersResources.Parentheses_can_be_removed), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)),
isUnnecessary: true); isUnnecessary: true);
/// <summary>
/// This analyzer inserts the fade locations into indices 1 and 2 inside additional locations.
/// </summary>
private static readonly ImmutableDictionary<string, IEnumerable<int>> s_fadeLocations = ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 1, 2 });
protected AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer() protected AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer()
: base(ImmutableArray.Create(s_diagnosticDescriptor)) : base(ImmutableArray.Create(s_diagnosticDescriptor))
{ {
...@@ -120,7 +113,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) ...@@ -120,7 +113,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
var severity = preference.Notification.Severity; var severity = preference.Notification.Severity;
var additionalLocations = ImmutableArray.Create( var additionalLocations = ImmutableArray.Create(
parenthesizedExpression.GetLocation(), parenthesizedExpression.GetLocation());
var additionalUnnecessaryLocations = ImmutableArray.Create(
parenthesizedExpression.GetFirstToken().GetLocation(), parenthesizedExpression.GetFirstToken().GetLocation(),
parenthesizedExpression.GetLastToken().GetLocation()); parenthesizedExpression.GetLastToken().GetLocation());
...@@ -129,7 +123,7 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) ...@@ -129,7 +123,7 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
GetDiagnosticSquiggleLocation(parenthesizedExpression, context.CancellationToken), GetDiagnosticSquiggleLocation(parenthesizedExpression, context.CancellationToken),
severity, severity,
additionalLocations, additionalLocations,
s_fadeLocations)); additionalUnnecessaryLocations));
} }
/// <summary> /// <summary>
......
...@@ -2,9 +2,7 @@ ...@@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars;
...@@ -67,13 +65,17 @@ private void AnalyzeInterpolation(OperationAnalysisContext context) ...@@ -67,13 +65,17 @@ private void AnalyzeInterpolation(OperationAnalysisContext context)
return; return;
} }
// The diagnostic itself fades the first unnecessary location, and the remaining locations are passed as
// additional unnecessary locations.
var firstUnnecessaryLocation = unnecessaryLocations[0];
var remainingUnnecessaryLocations = unnecessaryLocations.RemoveAt(0);
context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
Descriptor, Descriptor,
unnecessaryLocations.First(), firstUnnecessaryLocation,
option.Notification.Severity, option.Notification.Severity,
additionalLocations: ImmutableArray.Create(interpolation.Syntax.GetLocation()).AddRange(unnecessaryLocations.Skip(1)), additionalLocations: ImmutableArray.Create(interpolation.Syntax.GetLocation()),
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty additionalUnnecessaryLocations: remainingUnnecessaryLocations));
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), Enumerable.Range(1, unnecessaryLocations.Length - 1))));
} }
} }
} }
...@@ -5,13 +5,11 @@ ...@@ -5,13 +5,11 @@
#nullable enable #nullable enable
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseCollectionInitializer namespace Microsoft.CodeAnalysis.UseCollectionInitializer
{ {
...@@ -146,18 +144,20 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ien ...@@ -146,18 +144,20 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ien
if (syntaxFacts.IsInvocationExpression(expression)) if (syntaxFacts.IsInvocationExpression(expression))
{ {
var arguments = syntaxFacts.GetArgumentsOfInvocationExpression(expression); var arguments = syntaxFacts.GetArgumentsOfInvocationExpression(expression);
var location1 = Location.Create(syntaxTree, TextSpan.FromBounds( var additionalUnnecessaryLocations = ImmutableArray.Create(
match.SpanStart, arguments[0].SpanStart)); syntaxTree.GetLocation(TextSpan.FromBounds(match.SpanStart, arguments[0].SpanStart)),
syntaxTree.GetLocation(TextSpan.FromBounds(arguments.Last().FullSpan.End, match.Span.End)));
// Report the diagnostic at the first unnecessary location. This is the location where the code fix
// will be offered.
var location1 = additionalUnnecessaryLocations[0];
context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
Descriptor, Descriptor,
location1, location1,
ReportDiagnostic.Default, ReportDiagnostic.Default,
additionalLocations: locations additionalLocations: locations,
.Add(location1) additionalUnnecessaryLocations: additionalUnnecessaryLocations));
.Add(syntaxTree.GetLocation(TextSpan.FromBounds(arguments.Last().FullSpan.End, match.Span.End))),
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { locations.Length - 1, locations.Length })));
} }
} }
} }
......
...@@ -4,14 +4,12 @@ ...@@ -4,14 +4,12 @@
#nullable enable #nullable enable
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseObjectInitializer namespace Microsoft.CodeAnalysis.UseObjectInitializer
{ {
...@@ -132,11 +130,9 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context) ...@@ -132,11 +130,9 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
Descriptor, Descriptor,
location1, location1,
ReportDiagnostic.Default, ReportDiagnostic.Default,
additionalLocations: locations.Add(Location.Create(syntaxTree, TextSpan.FromBounds( additionalLocations: locations,
match.Initializer.FullSpan.End, additionalUnnecessaryLocations: ImmutableArray.Create(
match.Statement.Span.End))), syntaxTree.GetLocation(TextSpan.FromBounds(match.Initializer.FullSpan.End, match.Statement.Span.End)))));
tagIndices: ImmutableDictionary<string, IEnumerable<int>>.Empty
.Add(nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { locations.Length })));
} }
else else
{ {
......
...@@ -65,8 +65,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName ...@@ -65,8 +65,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName
Descriptor, Descriptor,
nameColonEquals.GetLocation(), nameColonEquals.GetLocation(),
preference.Notification.Severity, preference.Notification.Severity,
additionalLocations:={syntaxTree.GetLocation(fadeSpan)}, additionalLocations:=ImmutableArray(Of Location).Empty,
tagIndices:=ImmutableDictionary(Of String, IEnumerable(Of Integer)).Empty.Add(NameOf(WellKnownDiagnosticTags.Unnecessary), {0}))) additionalUnnecessaryLocations:=ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))))
End Sub End Sub
Private Sub ReportDiagnosticsIfNeeded( Private Sub ReportDiagnosticsIfNeeded(
...@@ -95,8 +95,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName ...@@ -95,8 +95,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseInferredMemberName
Descriptor, Descriptor,
syntaxTree.GetLocation(fadeSpan), syntaxTree.GetLocation(fadeSpan),
preference.Notification.Severity, preference.Notification.Severity,
additionalLocations:={syntaxTree.GetLocation(fadeSpan)}, additionalLocations:=ImmutableArray(Of Location).Empty,
tagIndices:=ImmutableDictionary(Of String, IEnumerable(Of Integer)).Empty.Add(NameOf(WellKnownDiagnosticTags.Unnecessary), {0}))) additionalUnnecessaryLocations:=ImmutableArray.Create(syntaxTree.GetLocation(fadeSpan))))
End Sub End Sub
End Class End Class
End Namespace End Namespace
...@@ -59,12 +59,6 @@ public async Task Test_FadingSpans() ...@@ -59,12 +59,6 @@ public async Task Test_FadingSpans()
private class Analyzer : DiagnosticAnalyzer private class Analyzer : DiagnosticAnalyzer
{ {
// Mark elements 1, and 2 in the locations as the fading locations.
private static readonly ImmutableDictionary<string, IEnumerable<int>> s_fadeLocations = new Dictionary<string, IEnumerable<int>>
{
{ nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 1, 2 } },
}.ToImmutableDictionary();
private readonly DiagnosticDescriptor _rule = new DiagnosticDescriptor( private readonly DiagnosticDescriptor _rule = new DiagnosticDescriptor(
"test", "test", "test", "test", DiagnosticSeverity.Error, true, "test", "test", "test", "test", DiagnosticSeverity.Error, true,
customTags: DiagnosticCustomTags.Create(isUnnecessary: true, isConfigurable: false)); customTags: DiagnosticCustomTags.Create(isUnnecessary: true, isConfigurable: false));
...@@ -76,15 +70,16 @@ public override void Initialize(AnalysisContext context) ...@@ -76,15 +70,16 @@ public override void Initialize(AnalysisContext context)
{ {
context.RegisterSyntaxTreeAction(c => context.RegisterSyntaxTreeAction(c =>
{ {
var additionalLocations = ImmutableArray.Create(Location.Create(c.Tree, new TextSpan(0, 10)));
var additionalUnnecessaryLocations = ImmutableArray.Create(
Location.Create(c.Tree, new TextSpan(0, 1)),
Location.Create(c.Tree, new TextSpan(9, 1)));
c.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( c.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
_rule, Location.Create(c.Tree, new TextSpan(0, 10)), _rule, Location.Create(c.Tree, new TextSpan(0, 10)),
ReportDiagnostic.Error, ReportDiagnostic.Error,
new Location[] { additionalLocations,
Location.Create(c.Tree, new TextSpan(0, 10)), additionalUnnecessaryLocations));
Location.Create(c.Tree, new TextSpan(0, 1)),
Location.Create(c.Tree, new TextSpan(9, 1)),
},
s_fadeLocations));
}); });
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册