// 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.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
///
/// Represents top-level light bulb menu item for the suppression fix.
/// The top-level item itself does nothing. It doesn't display a preview and can't be invoked / applied.
/// The top-level item is simply a container for the fixes displayed as sub-menu items.
///
internal sealed class SuppressionSuggestedAction : SuggestedAction, ITelemetryDiagnosticID
{
private readonly CodeFix _fix;
private readonly Func _getFixAllSuggestedActionSet;
public SuppressionSuggestedAction(
Workspace workspace,
ITextBuffer subjectBuffer,
ICodeActionEditHandlerService editHandler,
IWaitIndicator waitIndicator,
CodeFix fix,
object provider,
Func getFixAllSuggestedActionSet,
IAsynchronousOperationListener operationListener)
: base(workspace, subjectBuffer, editHandler, waitIndicator,
provider, operationListener, fix.Action)
{
_fix = fix;
_getFixAllSuggestedActionSet = getFixAllSuggestedActionSet;
}
// Put suppressions at the end of everything.
internal override CodeActionPriority Priority => CodeActionPriority.None;
public override bool HasActionSets
{
get
{
return this.CodeAction.GetCodeActions().Any();
}
}
private IEnumerable _actionSets;
public override Task> GetActionSetsAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (_actionSets != null)
{
return Task.FromResult(_actionSets);
}
if (this.CodeAction.GetCodeActions().Any())
{
var nestedSuggestedActions = ArrayBuilder.GetInstance();
var fixCount = this.CodeAction.GetCodeActions().Length;
foreach (var action in this.CodeAction.GetCodeActions())
{
cancellationToken.ThrowIfCancellationRequested();
var fixAllSuggestedActionSet = _getFixAllSuggestedActionSet(action);
nestedSuggestedActions.Add(new CodeFixSuggestedAction(
this.Workspace, this.SubjectBuffer, this.EditHandler, this.WaitIndicator,
new CodeFix(_fix.Project, action, _fix.Diagnostics),
this.Provider, fixAllSuggestedActionSet, this.OperationListener, action));
}
_actionSets = ImmutableArray.Create(
new SuggestedActionSet(nestedSuggestedActions.ToImmutableAndFree()));
return Task.FromResult(_actionSets);
}
return SpecializedTasks.Default>();
}
protected override Task InvokeAsync(
IProgressTracker progressTracker, CancellationToken cancellationToken)
{
// The top-level action cannot be invoked.
// However, the nested sub-actions returned above can be.
throw new NotSupportedException(string.Format(EditorFeaturesResources._0_does_not_support_the_1_operation_However_it_may_contain_nested_2_s_see_2_3_that_support_this_operation,
nameof(SuppressionSuggestedAction),
nameof(Invoke),
nameof(ISuggestedAction),
nameof(GetActionSetsAsync)));
}
public string GetDiagnosticID()
{
var diagnostic = _fix.PrimaryDiagnostic;
// we log diagnostic id as it is if it is from us
if (diagnostic.Descriptor.CustomTags.Any(t => t == WellKnownDiagnosticTags.Telemetry))
{
return diagnostic.Id;
}
// if it is from third party, we use hashcode
return diagnostic.Id.GetHashCode().ToString(CultureInfo.InvariantCulture);
}
}
}