SuppressionSuggestedAction.cs 4.8 KB
Newer Older
1 2 3 4 5 6 7 8
// 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;
9
using System.Threading.Tasks;
10
using Microsoft.CodeAnalysis.CodeActions;
11
using Microsoft.CodeAnalysis.CodeFixes;
12
using Microsoft.CodeAnalysis.Editor.Host;
13
using Microsoft.CodeAnalysis.Shared.TestHooks;
14
using Microsoft.CodeAnalysis.Shared.Utilities;
15 16
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
17
using Roslyn.Utilities;
18 19 20 21 22 23 24 25

namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
    /// <summary>
    /// 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.
    /// </summary>
26
    internal sealed class SuppressionSuggestedAction : SuggestedAction, ITelemetryDiagnosticID<string>
27 28
    {
        private readonly CodeFix _fix;
29
        private readonly Func<CodeAction, SuggestedActionSet> _getFixAllSuggestedActionSet;
30 31 32 33 34

        public SuppressionSuggestedAction(
            Workspace workspace,
            ITextBuffer subjectBuffer,
            ICodeActionEditHandlerService editHandler,
35
            IWaitIndicator waitIndicator,
36
            CodeFix fix,
37
            object provider,
38 39
            Func<CodeAction, SuggestedActionSet> getFixAllSuggestedActionSet,
            IAsynchronousOperationListener operationListener)
40 41
            : base(workspace, subjectBuffer, editHandler, waitIndicator, 
                   provider, operationListener, fix.Action)
42 43
        {
            _fix = fix;
44
            _getFixAllSuggestedActionSet = getFixAllSuggestedActionSet;
45 46
        }

47 48 49
        // Put suppressions at the end of everything.
        internal override CodeActionPriority Priority => CodeActionPriority.None;

50
        public override bool HasActionSets
51 52 53
        {
            get
            {
54
                return this.CodeAction.GetCodeActions().Any();
55 56
            }
        }
57

58 59 60 61
        private IEnumerable<SuggestedActionSet> _actionSets;
        public override Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
62

63 64 65 66 67
            if (_actionSets != null)
            {
                return Task.FromResult(_actionSets);
            }

68
            if (this.CodeAction.GetCodeActions().Any())
69
            {
70
                var nestedSuggestedActions = ArrayBuilder<SuggestedAction>.GetInstance();
71
                var fixCount = this.CodeAction.GetCodeActions().Length;
72

73
                foreach (var action in this.CodeAction.GetCodeActions())
74 75 76
                {
                    cancellationToken.ThrowIfCancellationRequested();

77
                    var fixAllSuggestedActionSet = _getFixAllSuggestedActionSet(action);
78
                    nestedSuggestedActions.Add(new CodeFixSuggestedAction(
79 80 81
                        this.Workspace, this.SubjectBuffer, this.EditHandler, this.WaitIndicator, 
                        new CodeFix(_fix.Project, action, _fix.Diagnostics),
                        this.Provider, fixAllSuggestedActionSet, this.OperationListener, action));
82 83
                }

84
                _actionSets = ImmutableArray.Create(
85
                    new SuggestedActionSet(nestedSuggestedActions.ToImmutableAndFree()));
86 87

                return Task.FromResult(_actionSets);
88
            }
89 90

            return SpecializedTasks.Default<IEnumerable<SuggestedActionSet>>();
91 92
        }

93 94
        protected override Task InvokeAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
95 96 97
        {
            // The top-level action cannot be invoked.
            // However, the nested sub-actions returned above can be.
98
            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,
99 100 101
                nameof(SuppressionSuggestedAction),
                nameof(Invoke),
                nameof(ISuggestedAction),
102 103 104
                nameof(GetActionSetsAsync)));
        }

105 106 107 108 109 110 111 112 113 114 115
        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
116
            return diagnostic.Id.GetHashCode().ToString(CultureInfo.InvariantCulture);
117 118 119
        }
    }
}