SuppressionSuggestedAction.cs 4.7 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 40
            Func<CodeAction, SuggestedActionSet> getFixAllSuggestedActionSet,
            IAsynchronousOperationListener operationListener)
            : base(workspace, subjectBuffer, editHandler, waitIndicator, fix.Action, provider, operationListener)
41 42
        {
            _fix = fix;
43
            _getFixAllSuggestedActionSet = getFixAllSuggestedActionSet;
44 45
        }

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

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

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

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

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

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

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

82
                _actionSets = ImmutableArray.Create(
83
                    new SuggestedActionSet(nestedSuggestedActions.ToImmutableAndFree()));
84 85

                return Task.FromResult(_actionSets);
86
            }
87 88

            return SpecializedTasks.Default<IEnumerable<SuggestedActionSet>>();
89 90
        }

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

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