提交 fa86a5dd 编写于 作者: M Manish Vasani

Merge pull request #4663 from mavasani/Issue3311

Add EquivalenceKey for suppression code actions to ensure that duplicate equivalent suppression fixes are not shown.

Fixes #3311 
......@@ -2,15 +2,23 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeFixes.Suppression;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeFixes.Suppression;
using Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.CSharp;
using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.ErrorLogger;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.Suppression
......@@ -151,6 +159,49 @@ void Method()
}}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
[WorkItem(3311, "https://github.com/dotnet/roslyn/issues/3311")]
public void TestNoDuplicateSuppressionCodeFixes()
{
var source = @"
class Class
{
void Method()
{
[|int x = 0, y = 0;|]
}
}";
using (var workspace = CreateWorkspaceFromFile(source, parseOptions: null, compilationOptions: null))
{
var diagnosticService = new TestDiagnosticAnalyzerService(LanguageNames.CSharp, new CSharpCompilerDiagnosticAnalyzer());
var incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace);
var suppressionProvider = CreateDiagnosticProviderAndFixer(workspace).Item2;
var suppressionProviderFactory = new Lazy<ISuppressionFixProvider, CodeChangeProviderMetadata>(() => suppressionProvider,
new CodeChangeProviderMetadata("SuppressionProvider", languages: new[] { LanguageNames.CSharp }));
var fixService = new CodeFixService(diagnosticService,
SpecializedCollections.EmptyEnumerable<Lazy<IErrorLoggerService>>(),
SpecializedCollections.EmptyEnumerable<Lazy<CodeFixProvider, CodeChangeProviderMetadata>>(),
SpecializedCollections.SingletonEnumerable(suppressionProviderFactory));
TextSpan span;
var document = GetDocumentAndSelectSpan(workspace, out span);
var diagnostics = diagnosticService.GetDiagnosticsForSpanAsync(document, span, CancellationToken.None)
.WaitAndGetResult(CancellationToken.None)
.Where(d => d.Id == "CS0219");
Assert.Equal(2, diagnostics.Count());
var fixes = fixService.GetFixesAsync(document, span, includeSuppressionFixes: true, cancellationToken: CancellationToken.None)
.WaitAndGetResult(CancellationToken.None)
.SelectMany(fixCollection => fixCollection.Fixes)
.Where(fix => fix.PrimaryDiagnostic.Id == "CS0219");
// Ensure that both the fixes have identical equivalence key, and hence get de-duplicated in LB menu.
Assert.Equal(2, fixes.Count());
Assert.NotNull(fixes.First().Action.EquivalenceKey);
Assert.Equal(fixes.First().Action.EquivalenceKey, fixes.Last().Action.EquivalenceKey);
}
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
public void TestErrorAndWarningScenario()
{
......
......@@ -41,13 +41,8 @@ protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperation
};
}
public override string Title
{
get
{
return _title;
}
}
public override string Title => _title;
public override string EquivalenceKey => _title + _diagnostic.Id;
private async Task<Document> GetChangedSuppressionDocumentAsync(CancellationToken cancellationToken)
{
......
......@@ -36,21 +36,10 @@ protected async override Task<Document> GetChangedDocumentAsync(CancellationToke
return _document.WithSyntaxRoot(newRoot);
}
public override string Title
{
get
{
return _title;
}
}
public override string Title => _title;
public override string EquivalenceKey => _title + _diagnostic.Id;
internal SyntaxNode TargetNode_TestOnly
{
get
{
return _targetNode;
}
}
internal SyntaxNode TargetNode_TestOnly => _targetNode;
}
}
}
......@@ -153,23 +153,11 @@ private static SyntaxToken GetNewEndToken(SyntaxToken endToken, Diagnostic diagn
}
}
public override string Title
{
get
{
return _title;
}
}
public override string Title => _title;
public override string EquivalenceKey => _title + _diagnostic.Id;
public SyntaxToken StartToken_TestOnly
{
get { return _startToken; }
}
public SyntaxToken EndToken_TestOnly
{
get { return _endToken; }
}
public SyntaxToken StartToken_TestOnly => _startToken;
public SyntaxToken EndToken_TestOnly => _endToken;
}
}
}
// 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.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CodeActions;
namespace Microsoft.CodeAnalysis.CodeFixes.Suppression
......@@ -8,20 +9,33 @@ namespace Microsoft.CodeAnalysis.CodeFixes.Suppression
internal sealed class SuppressionCodeAction : CodeAction
{
private readonly string _title;
public override string Title
{
get
{
return _title;
}
}
private readonly string _equivalenceKey;
public readonly IEnumerable<CodeAction> NestedActions;
public SuppressionCodeAction(Diagnostic diagnostic, IEnumerable<CodeAction> nestedActions)
{
_title = string.Format(FeaturesResources.SuppressionCodeActionTitle, diagnostic.Id);
_equivalenceKey = ComputeEquivalenceKey(nestedActions);
this.NestedActions = nestedActions;
}
public override string Title => _title;
public override string EquivalenceKey => _equivalenceKey;
private static string ComputeEquivalenceKey(IEnumerable<CodeAction> nestedActions)
{
if (nestedActions == null)
{
return null;
}
var equivalenceKey = string.Empty;
foreach (var action in nestedActions)
{
equivalenceKey += (action.EquivalenceKey ?? action.GetHashCode().ToString() + ";");
}
return equivalenceKey;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册