SuppressionSuggestedAction.cs 5.1 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 15
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
16
using Roslyn.Utilities;
17 18 19 20 21 22 23 24 25 26 27

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>
    internal class SuppressionSuggestedAction : SuggestedAction, ITelemetryDiagnosticID<string>
    {
        private readonly CodeFix _fix;
28
        private readonly Func<CodeAction, SuggestedActionSet> _getFixAllSuggestedActionSet;
29 30 31 32 33

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

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

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

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

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

66
            if (this.CodeAction.GetCodeActions().Any())
67 68
            {
                var nestedSuggestedActions = ImmutableArray.CreateBuilder<SuggestedAction>();
69
                var fixCount = this.CodeAction.GetCodeActions().Length;
70

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

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

81 82 83 84
                _actionSets = ImmutableArray.Create(
                    new SuggestedActionSet(nestedSuggestedActions.ToImmutable()));

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

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

90
        protected override Task InvokeAsync(CancellationToken cancellationToken)
91 92 93 94 95 96 97
        {
            // The top-level action cannot be invoked.
            // However, the nested sub-actions returned above can be.
            throw new NotSupportedException(string.Format(EditorFeaturesResources.OperationNotSupported,
                nameof(SuppressionSuggestedAction),
                nameof(Invoke),
                nameof(ISuggestedAction),
98 99 100 101 102 103 104 105 106 107 108
                nameof(GetActionSetsAsync)));
        }

        public override bool HasPreview
        {
            get
            {
                // The top-level action won't show any preview.
                // However, the nested sub-actions returned above will show preview.
                return false;
            }
109 110
        }

111
        public override Task<object> GetPreviewAsync(CancellationToken cancellationToken)
112 113 114
        {
            // The top-level action won't show any preview.
            // However, the nested sub-actions returned above will show preview.
115
            return SpecializedTasks.Default<object>();
116 117 118 119 120 121 122 123 124 125 126 127 128
        }

        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
129
            return diagnostic.Id.GetHashCode().ToString(CultureInfo.InvariantCulture);
130 131 132
        }
    }
}