未验证 提交 7650489c 编写于 作者: D David 提交者: GitHub

Issue 27925 - Squiggle first line / entire parenthetical expression in remove...

Issue 27925 - Squiggle first line / entire parenthetical expression in remove unnecessary parentheses diagnostic (#32500)

* Update unnecessary parentheses analyzer to squiggle the entire
expression / first line.
Resolves #27925 
上级 0137cfab
......@@ -2135,7 +2135,7 @@ void Goo()
public async Task TestAttribute()
{
var input = @"[ assembly : [|Guid|] ( ""9ed54f84-a89d-4fcd-a854-44251e925f09"" ) ] ";
await TestActionCountAsync(input, 1);
await TestActionCountAsync(input, 2);
await TestAsync(
input,
......
......@@ -4394,7 +4394,7 @@ void Goo()
{
}
}",
count: 3);
count: 6);
}
[WorkItem(543061, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543061")]
......
......@@ -1052,7 +1052,7 @@ static void Main(string[] args)
public async Task TestAttribute()
{
var input = @"[ assembly : [|Guid|] ( ""9ed54f84-a89d-4fcd-a854-44251e925f09"" ) ] ";
await TestActionCountAsync(input, 1);
await TestActionCountAsync(input, 2);
await TestInRegularAndScriptAsync(
input,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryParentheses;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -17,13 +19,13 @@ public partial class RemoveUnnecessaryParenthesesTests : AbstractCSharpDiagnosti
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpRemoveUnnecessaryParenthesesDiagnosticAnalyzer(), new CSharpRemoveUnnecessaryParenthesesCodeFixProvider());
private async Task TestAsync(string initial, string expected, bool offeredWhenRequireForClarityIsEnabled)
private async Task TestAsync(string initial, string expected, bool offeredWhenRequireForClarityIsEnabled, int index = 0)
{
await TestInRegularAndScriptAsync(initial, expected, options: RemoveAllUnnecessaryParentheses);
await TestInRegularAndScriptAsync(initial, expected, options: RemoveAllUnnecessaryParentheses, index: index);
if (offeredWhenRequireForClarityIsEnabled)
{
await TestInRegularAndScriptAsync(initial, expected, options: RequireAllParenthesesForClarity);
await TestInRegularAndScriptAsync(initial, expected, options: RequireAllParenthesesForClarity, index: index);
}
else
{
......@@ -31,6 +33,17 @@ private async Task TestAsync(string initial, string expected, bool offeredWhenRe
}
}
internal override bool ShouldSkipMessageDescriptionVerification(DiagnosticDescriptor descriptor)
{
return descriptor.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary) && descriptor.DefaultSeverity == DiagnosticSeverity.Hidden;
}
private DiagnosticDescription GetRemoveUnnecessaryParenthesesDiagnostic(string text, int line, int column)
{
var diagnosticId = IDEDiagnosticIds.RemoveUnnecessaryParenthesesDiagnosticId;
return TestHelpers.Diagnostic(diagnosticId, text, startLocation: new LinePosition(line, column));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)]
public async Task TestVariableInitializer_TestWithAllOptionsSetToIgnore()
{
......@@ -388,7 +401,7 @@ void M()
{
int i = ( 1 + 2 );
}
}", offeredWhenRequireForClarityIsEnabled: true);
}", offeredWhenRequireForClarityIsEnabled: true, index: 1);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)]
......@@ -2064,7 +2077,7 @@ void M()
#endif
}
}",
offeredWhenRequireForClarityIsEnabled: true);
offeredWhenRequireForClarityIsEnabled: true, index: 1);
}
[WorkItem(29454, "https://github.com/dotnet/roslyn/issues/29454")]
......@@ -2276,9 +2289,90 @@ public async Task TestMissingForNestedConditionalExpressionInLambda()
void Test(bool a)
{
Func<int, string> lambda =
number => (number + $""{ ($$a ? ""foo"" : ""bar"") }"");
number => number + $""{ ($$a ? ""foo"" : ""bar"") }"";
}
}", new TestParameters(options: RemoveAllUnnecessaryParentheses));
}
[WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)]
public async Task TestUnnecessaryParenthesisDiagnosticSingleLineExpression()
{
var openParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 4, 16);
var parentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + 2)", 4, 16);
var closeParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 4, 22);
await TestDiagnosticsAsync(
@"class C
{
void M()
{
int x = [|(1 + 2)|];
}
}", new TestParameters(options: RemoveAllUnnecessaryParentheses), parentheticalExpressionDiagnostic, openParenthesesDiagnostic, closeParenthesesDiagnostic);
}
[WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)]
public async Task TestUnnecessaryParenthesisDiagnosticInMultiLineExpression()
{
var openParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 4, 16);
var firstLineParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 +", 4, 16);
var closeParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 5, 13);
await TestDiagnosticsAsync(
@"class C
{
void M()
{
int x = [|(1 +
2)|];
}
}", new TestParameters(options: RemoveAllUnnecessaryParentheses), firstLineParentheticalExpressionDiagnostic, openParenthesesDiagnostic, closeParenthesesDiagnostic);
}
[WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)]
public async Task TestUnnecessaryParenthesisDiagnosticInNestedExpression()
{
var outerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 4, 16);
var outerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + (2 + 3) + 4)", 4, 16);
var outerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 4, 32);
var innerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 4, 21);
var innerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(2 + 3)", 4, 21);
var innerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 4, 27);
var expectedDiagnostics = new DiagnosticDescription[] { outerParentheticalExpressionDiagnostic, outerOpenParenthesesDiagnostic,
outerCloseParenthesesDiagnostic, innerParentheticalExpressionDiagnostic, innerOpenParenthesesDiagnostic, innerCloseParenthesesDiagnostic };
await TestDiagnosticsAsync(
@"class C
{
void M()
{
int x = [|(1 + (2 + 3) + 4)|];
}
}", new TestParameters(options: RemoveAllUnnecessaryParentheses), expectedDiagnostics);
}
[WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)]
public async Task TestUnnecessaryParenthesisDiagnosticInNestedMultiLineExpression()
{
var outerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 4, 16);
var outerFirstLineParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + 2 +", 4, 16);
var outerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 6, 17);
var innerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 5, 12);
var innerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(3 + 4)", 5, 12);
var innerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 5, 18);
var expectedDiagnostics = new DiagnosticDescription[] { outerFirstLineParentheticalExpressionDiagnostic, outerOpenParenthesesDiagnostic,
outerCloseParenthesesDiagnostic, innerParentheticalExpressionDiagnostic, innerOpenParenthesesDiagnostic, innerCloseParenthesesDiagnostic };
await TestDiagnosticsAsync(
@"class C
{
void M()
{
int x = [|(1 + 2 +
(3 + 4) +
5 + 6)|];
}
}", new TestParameters(options: RemoveAllUnnecessaryParentheses), expectedDiagnostics);
}
}
}
......@@ -38,6 +38,19 @@ internal virtual (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderA
: CreateDiagnosticProviderAndFixer(workspace, parameters);
}
internal virtual bool ShouldSkipMessageDescriptionVerification(DiagnosticDescriptor descriptor)
{
if (descriptor.CustomTags.Contains(WellKnownDiagnosticTags.NotConfigurable))
{
if (!descriptor.IsEnabledByDefault || descriptor.DefaultSeverity == DiagnosticSeverity.Hidden)
{
// The message only displayed if either enabled and not hidden, or configurable
return true;
}
}
return false;
}
[Fact]
public void TestSupportedDiagnosticsMessageTitle()
{
......@@ -75,13 +88,9 @@ public void TestSupportedDiagnosticsMessageDescription()
foreach (var descriptor in diagnosticAnalyzer.SupportedDiagnostics)
{
if (descriptor.CustomTags.Contains(WellKnownDiagnosticTags.NotConfigurable))
if (ShouldSkipMessageDescriptionVerification(descriptor))
{
if (!descriptor.IsEnabledByDefault || descriptor.DefaultSeverity == DiagnosticSeverity.Hidden)
{
// The message only displayed if either enabled and not hidden, or configurable
continue;
}
continue;
}
Assert.NotEqual("", descriptor.MessageFormat?.ToString() ?? "");
......
......@@ -193,20 +193,13 @@ protected Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, out stri
CancellationToken.None);
await fixer.RegisterCodeFixesAsync(context);
if (fixes.Count > 0)
{
break;
}
}
var actions = fixes.SelectAsArray(f => f.Action);
if (actions.Length == 1)
{
if (actions[0] is TopLevelSuppressionCodeAction suppressionAction)
{
actions = suppressionAction.NestedCodeActions;
}
}
actions = actions.SelectMany(a => a is TopLevelSuppressionCodeAction
? a.NestedCodeActions
: ImmutableArray.Create(a)).ToImmutableArray();
actions = MassageActions(actions);
......
......@@ -3,6 +3,7 @@
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryParentheses
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.RemoveUnnecessaryParentheses
......@@ -18,11 +19,21 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.RemoveUnnecessaryP
Return (New VisualBasicRemoveUnnecessaryParenthesesDiagnosticAnalyzer(), New VisualBasicRemoveUnnecessaryParenthesesCodeFixProvider())
End Function
Private Shadows Async Function TestAsync(initial As String, expected As String, offeredWhenRequireAllParenthesesForClarityIsEnabled As Boolean) As Task
Await TestInRegularAndScriptAsync(initial, expected, options:=RemoveAllUnnecessaryParentheses)
Friend Function GetRemoveUnnecessaryParenthesesDiagnostic(text As String, line As Integer, column As Integer) As DiagnosticDescription
Return TestHelpers.Diagnostic(IDEDiagnosticIds.RemoveUnnecessaryParenthesesDiagnosticId, text, startLocation:=New LinePosition(line, column))
End Function
Friend Overrides Function ShouldSkipMessageDescriptionVerification(descriptor As DiagnosticDescriptor) As Boolean
Return descriptor.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary) And descriptor.DefaultSeverity = DiagnosticSeverity.Hidden
End Function
Private Shadows Async Function TestAsync(initial As String, expected As String,
offeredWhenRequireAllParenthesesForClarityIsEnabled As Boolean,
Optional ByVal index As Integer = 0) As Task
Await TestInRegularAndScriptAsync(initial, expected, options:=RemoveAllUnnecessaryParentheses, index:=index)
If (offeredWhenRequireAllParenthesesForClarityIsEnabled) Then
Await TestInRegularAndScriptAsync(initial, expected, options:=MyBase.RequireAllParenthesesForClarity)
Await TestInRegularAndScriptAsync(initial, expected, options:=MyBase.RequireAllParenthesesForClarity, index:=index)
Else
Await TestMissingAsync(initial, parameters:=New TestParameters(options:=MyBase.RequireAllParenthesesForClarity))
End If
......@@ -297,7 +308,7 @@ end class",
sub M()
dim i = ( 1 + 2 )
end sub
end class", offeredWhenRequireAllParenthesesForClarityIsEnabled:=True)
end class", offeredWhenRequireAllParenthesesForClarityIsEnabled:=True, index:=1)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)>
......@@ -545,5 +556,74 @@ end class",
end sub
end class", parameters:=New TestParameters(options:=RemoveAllUnnecessaryParentheses))
End Function
<WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)>
Public Async Function TestUnnecessaryParenthesisDiagnosticSingleLineExpression() As Task
Dim openParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 2, 16)
Dim parentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + 2)", 2, 16)
Dim closeParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 2, 22)
Await TestDiagnosticsAsync(
"class C
sub M()
dim x = [|(1 + 2)|]
end sub
end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), parentheticalExpressionDiagnostic, openParenthesesDiagnostic, closeParenthesesDiagnostic)
End Function
<WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)>
Public Async Function TestUnnecessaryParenthesisDiagnosticInMultiLineExpression() As Task
Dim openParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 2, 16)
Dim firstLineParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 +", 2, 16)
Dim closeParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 3, 13)
Await TestDiagnosticsAsync(
"class C
sub M()
dim x = [|(1 +
2)|]
end sub
end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), firstLineParentheticalExpressionDiagnostic, openParenthesesDiagnostic, closeParenthesesDiagnostic)
End Function
<WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)>
Public Async Function TestUnnecessaryParenthesisDiagnosticInNestedExpression() As Task
Dim outerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 2, 16)
Dim outerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + (2 + 3) + 4)", 2, 16)
Dim outerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 2, 32)
Dim innerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 2, 21)
Dim innerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(2 + 3)", 2, 21)
Dim innerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 2, 27)
Dim expectedDiagnostics = New DiagnosticDescription() {outerParentheticalExpressionDiagnostic, outerOpenParenthesesDiagnostic,
outerCloseParenthesesDiagnostic, innerParentheticalExpressionDiagnostic, innerOpenParenthesesDiagnostic, innerCloseParenthesesDiagnostic}
Await TestDiagnosticsAsync(
"class C
sub M()
dim x = [|(1 + (2 + 3) + 4)|]
end sub
end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), expectedDiagnostics)
End Function
<WorkItem(27925, "https://github.com/dotnet/roslyn/issues/27925")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)>
Public Async Function TestUnnecessaryParenthesisDiagnosticInNestedMultiLineExpression() As Task
Dim outerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 2, 16)
Dim outerFirstLineParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + 2 +", 2, 16)
Dim outerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 4, 17)
Dim innerOpenParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(", 3, 12)
Dim innerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(3 + 4)", 3, 12)
Dim innerCloseParenthesesDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic(")", 3, 18)
Dim expectedDiagnostics = New DiagnosticDescription() {outerFirstLineParentheticalExpressionDiagnostic, outerOpenParenthesesDiagnostic,
outerCloseParenthesesDiagnostic, innerParentheticalExpressionDiagnostic, innerOpenParenthesesDiagnostic, innerCloseParenthesesDiagnostic}
Await TestDiagnosticsAsync(
"class C
sub M()
dim x = [|(1 + 2 +
(3 + 4) +
5 + 6)|]
end sub
end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), expectedDiagnostics)
End Function
End Class
End Namespace
......@@ -4,6 +4,7 @@
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Options;
using Roslyn.Utilities;
using System.Collections.Immutable;
namespace Microsoft.CodeAnalysis.RemoveUnnecessaryParentheses
{
......@@ -15,6 +16,11 @@ internal abstract class AbstractParenthesesDiagnosticAnalyzer : AbstractBuiltInC
{
}
protected AbstractParenthesesDiagnosticAnalyzer(ImmutableArray<DiagnosticDescriptor> diagnosticDescriptors)
: base(diagnosticDescriptors)
{
}
protected PerLanguageOption<CodeStyleOption<ParenthesesPreference>> GetLanguageOption(PrecedenceKind precedenceKind)
{
switch (precedenceKind)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.RemoveUnnecessaryParentheses
{
......@@ -15,10 +19,27 @@ internal abstract class AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer<
where TLanguageKindEnum : struct
where TParenthesizedExpressionSyntax : SyntaxNode
{
/// <summary>
/// A diagnostic descriptor that will fade the span (but not put a message or squiggle).
/// </summary>
private static readonly DiagnosticDescriptor s_diagnosticWithFade = CreateDescriptorWithId(
IDEDiagnosticIds.RemoveUnnecessaryParenthesesDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Remove_unnecessary_parentheses), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
string.Empty,
isUnneccessary: true);
/// <summary>
/// A diagnostic descriptor used to squiggle and message the span, but will not fade.
/// </summary>
private static readonly DiagnosticDescriptor s_diagnosticWithoutFade = CreateDescriptorWithId(
IDEDiagnosticIds.RemoveUnnecessaryParenthesesDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Remove_unnecessary_parentheses), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Parentheses_can_be_removed), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
isUnneccessary: false);
protected AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer()
: base(IDEDiagnosticIds.RemoveUnnecessaryParenthesesDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Remove_unnecessary_parentheses), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Parentheses_can_be_removed), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
: base(ImmutableArray.Create(s_diagnosticWithFade, s_diagnosticWithoutFade))
{
}
......@@ -41,8 +62,8 @@ protected sealed override void InitializeWorker(AnalysisContext context)
private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
{
var syntaxTree = context.SemanticModel.SyntaxTree;
var cancellationTokan = context.CancellationToken;
var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationTokan).GetAwaiter().GetResult();
var cancellationToken = context.CancellationToken;
var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();
if (optionSet == null)
{
return;
......@@ -109,16 +130,35 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
var additionalLocations = ImmutableArray.Create(parenthesizedExpression.GetLocation());
// Fades the open parentheses character and reports the suggestion.
context.ReportDiagnostic(Diagnostic.Create(s_diagnosticWithFade, parenthesizedExpression.GetFirstToken().GetLocation(), additionalLocations));
// Generates diagnostic used to squiggle the parenthetical expression.
context.ReportDiagnostic(DiagnosticHelper.Create(
UnnecessaryWithSuggestionDescriptor,
parenthesizedExpression.GetFirstToken().GetLocation(),
s_diagnosticWithoutFade,
GetDiagnosticSquiggleLocation(parenthesizedExpression, cancellationToken),
severity,
additionalLocations,
properties: null));
context.ReportDiagnostic(Diagnostic.Create(
UnnecessaryWithoutSuggestionDescriptor,
parenthesizedExpression.GetLastToken().GetLocation(), additionalLocations));
// Fades the close parentheses character.
context.ReportDiagnostic(Diagnostic.Create(s_diagnosticWithFade, parenthesizedExpression.GetLastToken().GetLocation(), additionalLocations));
}
/// <summary>
/// Gets the span of text to squiggle underline.
/// If the expression is contained within a single line, the entire expression span is returned.
/// Otherwise it will return the span from the expression start to the end of the same line.
/// </summary>
private Location GetDiagnosticSquiggleLocation(TParenthesizedExpressionSyntax parenthesizedExpression, CancellationToken cancellationToken)
{
var parenthesizedExpressionLocation = parenthesizedExpression.GetLocation();
var lines = parenthesizedExpression.SyntaxTree.GetText(cancellationToken).Lines;
var expressionFirstLine = lines.GetLineFromPosition(parenthesizedExpressionLocation.SourceSpan.Start);
var textSpanEndPosition = Math.Min(parenthesizedExpressionLocation.SourceSpan.End, expressionFirstLine.Span.End);
return Location.Create(parenthesizedExpression.SyntaxTree, TextSpan.FromBounds(parenthesizedExpressionLocation.SourceSpan.Start, textSpanEndPosition));
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册