コード例 #1
0
        static async Task AddSuppressionMenuItems(CodeFixMenu menu, TextEditor editor, Diagnostic diag, TextSpan span)
        {
            var workspace   = editor.DocumentContext.AnalysisDocument.Project.Solution.Workspace;
            var language    = editor.DocumentContext.AnalysisDocument.Project.Language;
            var mefExporter = (IMefHostExportProvider)workspace.Services.HostServices;

            //TODO: cache this
            var suppressionProviders = mefExporter.GetExports <ISuppressionFixProvider, CodeChangeProviderMetadata> ()
                                       .ToPerLanguageMapWithMultipleLanguages();

            foreach (var suppressionProvider in suppressionProviders[LanguageNames.CSharp].Select(lz => lz.Value))
            {
                if (!suppressionProvider.CanBeSuppressedOrUnsuppressed(diag))
                {
                    continue;
                }
                try {
                    var fixes = await suppressionProvider.GetSuppressionsAsync(editor.DocumentContext.AnalysisDocument, span, new [] { diag }, default(CancellationToken)).ConfigureAwait(false);

                    foreach (var fix in fixes)
                    {
                        AddFixMenuItem(editor, menu, fix.Action);
                    }
                } catch (Exception e) {
                    LoggingService.LogError("Error while adding fixes", e);
                }
            }
        }
コード例 #2
0
        static void AddFixMenuItem(TextEditor editor, CodeFixMenu menu, CodeFixMenu fixAllMenu, ref int mnemonic, CodeAction fix, FixAllState fixState, CancellationToken token)
        {
            if (fix is CodeAction.CodeActionWithNestedActions nested)
            {
                // Inline code actions if they are, otherwise add a nested fix menu
                if (nested.IsInlinable)
                {
                    int actionCount = nested.NestedCodeActions.Length;
                    foreach (var nestedFix in nested.NestedCodeActions)
                    {
                        var nestedFixState = actionCount > 1 && nestedFix.EquivalenceKey == null ? null : fixState;

                        AddFixMenuItem(editor, menu, fixAllMenu, ref mnemonic, nestedFix, nestedFixState, token);
                    }
                    return;
                }

                if (nested.NestedCodeActions.Length > 0)
                {
                    AddNestedFixMenu(editor, menu, fixAllMenu, nested, fixState, token);
                }
                return;
            }

            menu.Add(CreateFixMenuEntry(editor, fix, ref mnemonic));

            // TODO: Add support for more than doc when we have global undo.
            fixState = fixState?.WithScopeAndEquivalenceKey(FixAllScope.Document, fix.EquivalenceKey);
            var fixAllMenuEntry = CreateFixAllMenuEntry(editor, fixState, ref mnemonic, token);

            if (fixAllMenuEntry != null)
            {
                fixAllMenu.Add(fixAllMenuEntry);
            }
        }
コード例 #3
0
        bool ShowFixesMenu(Widget parent, Gdk.Rectangle evt, CodeFixMenu entrySet)
        {
            if (parent == null || parent.GdkWindow == null)
            {
                Editor.SuppressTooltips = false;
                return(true);
            }

            try {
                parent.GrabFocus();
                int x, y;
                x = evt.X;
                y = evt.Y;

                // Explicitly release the grab because the menu is shown on the mouse position, and the widget doesn't get the mouse release event
                Gdk.Pointer.Ungrab(Gtk.Global.CurrentEventTime);
                var menu = CreateContextMenu(entrySet);
                RefactoringPreviewTooltipWindow.HidePreviewTooltip();
                menu.Show(parent, x, y, () => {
                    Editor.SuppressTooltips = false;
                    RefactoringPreviewTooltipWindow.HidePreviewTooltip();
                    FixesMenuClosed?.Invoke(this, EventArgs.Empty);
                }, true);
            } catch (Exception ex) {
                LoggingService.LogError("Error while context menu popup.", ex);
            }

            return(true);
        }
コード例 #4
0
        static void AddNestedFixMenu(TextEditor editor, CodeFixMenu menu, CodeAction.CodeActionWithNestedActions fixes)
        {
            int subMnemonic = 0;
            var subMenu     = new CodeFixMenu(fixes.Title);

            foreach (var fix in fixes.NestedCodeActions)
            {
                AddFixMenuItem(editor, subMenu, ref subMnemonic, fix);
            }
            menu.Add(subMenu);
        }
コード例 #5
0
        static void AddNestedFixMenu(Ide.Editor.TextEditor editor, CodeFixMenu menu, CodeFixMenu fixAllMenu, CodeAction.CodeActionWithNestedActions fixes, FixAllState fixState, CancellationToken token)
        {
            int subMnemonic = 0;
            var subMenu     = new CodeFixMenu(fixes.Title);

            foreach (var fix in fixes.NestedCodeActions)
            {
                AddFixMenuItem(editor, subMenu, fixAllMenu, ref subMnemonic, fix, fixState, token);
            }
            menu.Add(subMenu);
        }
コード例 #6
0
        static void AddFixMenuItem(TextEditor editor, CodeFixMenu menu, ref int mnemonic, CodeAction fix)
        {
            var nested = fix as CodeAction.CodeActionWithNestedActions;

            if (nested != null)
            {
                AddNestedFixMenu(editor, menu, nested);
                return;
            }

            menu.Add(CreateFixMenuEntry(editor, fix, ref mnemonic));
        }
コード例 #7
0
        static void AddMenuWithSeparatorIfNeeded(CodeFixMenu toAdd, CodeFixMenu into, ref bool first)
        {
            if (toAdd.Items.Count == 0)
            {
                return;
            }

            if (first)
            {
                into.Add(CodeFixMenuEntry.Separator);
            }
            into.Add(toAdd);
            first = false;
        }
コード例 #8
0
        ContextMenu CreateContextMenu(CodeFixMenu entrySet)
        {
            var menu = new ContextMenu();

            foreach (var item in entrySet.Items)
            {
                if (item == CodeFixMenuEntry.Separator)
                {
                    menu.Items.Add(new SeparatorContextMenuItem());
                    continue;
                }

                var menuItem = new ContextMenuItem(item.Label);
                menuItem.Context = item.Action;
                if (item.Action == null)
                {
                    if (!(item is CodeFixMenu itemAsMenu) || itemAsMenu.Items.Count <= 0)
                    {
                        menuItem.Sensitive = false;
                    }
                }
                var subMenu = item as CodeFixMenu;
                if (subMenu != null)
                {
                    menuItem.SubMenu   = CreateContextMenu(subMenu);
                    menuItem.Selected += delegate {
                        RefactoringPreviewTooltipWindow.HidePreviewTooltip();
                    };
                    menuItem.Deselected += delegate { RefactoringPreviewTooltipWindow.HidePreviewTooltip(); };
                }
                else
                {
                    menuItem.Clicked  += (sender, e) => ((System.Action)((ContextMenuItem)sender).Context)();
                    menuItem.Selected += (sender, e) => {
                        RefactoringPreviewTooltipWindow.HidePreviewTooltip();
                        if (item.ShowPreviewTooltip != null)
                        {
                            item.ShowPreviewTooltip(e);
                        }
                    };
                    menuItem.Deselected += delegate { RefactoringPreviewTooltipWindow.HidePreviewTooltip(); };
                }
                menu.Items.Add(menuItem);
            }
            menu.Closed += delegate { RefactoringPreviewTooltipWindow.HidePreviewTooltip(); };
            return(menu);
        }
コード例 #9
0
        public static async Task <CodeFixMenu> CreateFixMenu(TextEditor editor, CodeActionContainer fixes, CancellationToken cancellationToken = default(CancellationToken))
        {
            var menu = new CodeFixMenu();

            if (editor.DocumentContext.AnalysisDocument == null)
            {
                return(menu);
            }

            int mnemonic = 1;

            foreach (var fix in fixes.CodeFixActions.OrderByDescending(i => GetUsage(i.CodeAction.EquivalenceKey)))
            {
                AddFixMenuItem(editor, menu, ref mnemonic, fix.CodeAction);
            }

            bool first = true;

            foreach (var fix in fixes.CodeRefactoringActions)
            {
                if (first)
                {
                    if (menu.Items.Count > 0)
                    {
                        menu.Add(CodeFixMenuEntry.Separator);
                    }
                    first = false;
                }

                AddFixMenuItem(editor, menu, ref mnemonic, fix.CodeAction);
            }

            var warningsAtCaret = (await editor.DocumentContext.AnalysisDocument.GetSemanticModelAsync(cancellationToken))
                                  .GetDiagnostics(new TextSpan(editor.CaretOffset, 0))
                                  .Where(diag => diag.Severity == DiagnosticSeverity.Warning).ToList();

            var caretSpan = new TextSpan(editor.CaretOffset, 0);

            first = true;
            foreach (var warning in warningsAtCaret)
            {
                if (string.IsNullOrWhiteSpace(warning.Descriptor.Title.ToString()))
                {
                    continue;
                }
                var label   = GettextCatalog.GetString("_Options for \u2018{0}\u2019", warning.Descriptor.Title);
                var subMenu = new CodeFixMenu(label);

                await AddSuppressionMenuItems(subMenu, editor, warning, caretSpan);

                if (subMenu.Items.Count > 0)
                {
                    if (first)
                    {
                        menu.Add(CodeFixMenuEntry.Separator);
                        first = false;
                    }

                    menu.Add(subMenu);
                }
            }

            first = true;
            foreach (var diag in fixes.DiagnosticsAtCaret)
            {
                if (string.IsNullOrWhiteSpace(diag.Descriptor.Title.ToString()))
                {
                    continue;
                }

                var notConfigurable = DescriptorHasTag(diag.Descriptor, WellKnownDiagnosticTags.NotConfigurable);

                var label   = GettextCatalog.GetString("_Options for \u2018{0}\u2019", diag.Descriptor.Title);
                var subMenu = new CodeFixMenu(label);

                if (first)
                {
                    menu.Add(CodeFixMenuEntry.Separator);
                    first = false;
                }

                await AddSuppressionMenuItems(subMenu, editor, diag, caretSpan);

                var descriptor = BuiltInCodeDiagnosticProvider.GetCodeDiagnosticDescriptor(diag.Id);

                if (descriptor != null && IsConfigurable(diag.Descriptor))
                {
                    var optionsMenuItem = new CodeFixMenuEntry(GettextCatalog.GetString("_Configure Rule"),
                                                               delegate {
                        IdeApp.Workbench.ShowGlobalPreferencesDialog(null, "C#", dialog => {
                            var panel = dialog.GetPanel <CodeIssuePanel> ("C#");
                            if (panel == null)
                            {
                                return;
                            }
                            panel.Widget.SelectCodeIssue(diag.Descriptor.Id);
                        });
                    });
                    subMenu.Add(optionsMenuItem);
                }

                foreach (var fix in fixes.CodeFixActions.OrderByDescending(i => GetUsage(i.CodeAction.EquivalenceKey)))
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        return(null);
                    }
                    var provider = fix.Diagnostic.GetCodeFixProvider().GetFixAllProvider();
                    if (provider == null)
                    {
                        continue;
                    }

                    if (!provider.GetSupportedFixAllScopes().Contains(FixAllScope.Document))
                    {
                        continue;
                    }

                    var language = editor.DocumentContext.AnalysisDocument.Project.Language;
                    var diagnosticdDescriptor = fix.Diagnostic?.GetCodeDiagnosticDescriptor(language);
                    if (diagnosticdDescriptor == null)
                    {
                        continue;
                    }

                    var subMenu2 = new CodeFixMenu(GettextCatalog.GetString("Fix all"));

                    var diagnosticAnalyzer = diagnosticdDescriptor.GetProvider();
                    if (!diagnosticAnalyzer.SupportedDiagnostics.Contains(diag.Descriptor))
                    {
                        continue;
                    }

                    var menuItem = new CodeFixMenuEntry(
                        GettextCatalog.GetString("In _Document"),
                        async delegate { await FixAll(editor, fix, provider, diagnosticAnalyzer); }
                        );
                    subMenu2.Add(menuItem);
                    subMenu.Add(CodeFixMenuEntry.Separator);
                    subMenu.Add(subMenu2);
                }

                menu.Add(subMenu);
            }
            return(menu);
        }
コード例 #10
0
        static void AddFixMenuItem(TextEditor editor, CodeFixMenu menu, CodeAction fix)
        {
            int _m = 0;

            AddFixMenuItem(editor, menu, ref _m, fix);
        }
コード例 #11
0
        public static CodeFixMenu CreateFixMenu(Ide.Editor.TextEditor editor, CodeActionContainer fixes, CancellationToken cancellationToken = default(CancellationToken))
        {
            var menu = new CodeFixMenu();

            if (editor.DocumentContext.AnalysisDocument == null)
            {
                return(menu);
            }

            var options  = ((MonoDevelopWorkspaceDiagnosticAnalyzerProviderService)Ide.Composition.CompositionManager.Instance.GetExportedValue <IWorkspaceDiagnosticAnalyzerProviderService> ()).GetOptionsAsync().Result;
            int mnemonic = 1;

            var suppressLabel = GettextCatalog.GetString("_Suppress");
            var suppressMenu  = new CodeFixMenu(suppressLabel);

            var fixAllLabel = GettextCatalog.GetString("_Fix all");
            var fixAllMenu  = new CodeFixMenu(fixAllLabel);

            var configureLabel = GettextCatalog.GetString("_Options");
            var configureMenu  = new CodeFixMenu(configureLabel);
            var fixAllTasks    = new List <Task <CodeAction> > ();

            foreach (var cfa in fixes.CodeFixActions)
            {
                var scopes = cfa.SupportedScopes;

                // FIXME: No global undo yet to support fixall in project/solution
                var state = scopes.Contains(FixAllScope.Document) ? cfa.FixAllState : null;

                foreach (var fix in cfa.Fixes)
                {
                    var diag = fix.PrimaryDiagnostic;
                    if (options.TryGetDiagnosticDescriptor(diag.Id, out var descriptor) && !diag.Descriptor.IsEnabledByDefault)
                    {
                        continue;
                    }

                    bool isSuppress = fix.Action is TopLevelSuppressionCodeAction;

                    CodeFixMenu fixMenu;
                    FixAllState fixState;
                    if (isSuppress)
                    {
                        fixMenu  = suppressMenu;
                        fixState = null;
                    }
                    else
                    {
                        fixMenu  = menu;
                        fixState = state;
                    }

                    AddFixMenuItem(editor, fixMenu, fixAllMenu, ref mnemonic, fix.Action, fixState, cancellationToken);
                }
            }

            bool first = true;

            foreach (var refactoring in fixes.CodeRefactoringActions)
            {
                if (options.TryGetRefactoringDescriptor(refactoring.GetType(), out var descriptor) && !descriptor.IsEnabled)
                {
                    continue;
                }

                if (first)
                {
                    if (menu.Items.Count > 0)
                    {
                        menu.Add(CodeFixMenuEntry.Separator);
                    }
                    first = false;
                }

                foreach (var codeAction in refactoring.CodeActions)
                {
                    AddFixMenuItem(editor, menu, null, ref mnemonic, codeAction.action, null, cancellationToken);
                }
            }

            first = true;

            AddMenuWithSeparatorIfNeeded(fixAllMenu, menu, ref first);
            AddMenuWithSeparatorIfNeeded(suppressMenu, menu, ref first);
            AddMenuWithSeparatorIfNeeded(configureMenu, menu, ref first);

            if (!AnalysisOptions.AnalysisEnabled)
            {
                if (first)
                {
                    menu.Add(CodeFixMenuEntry.Separator);
                }

                var enableLabel = GettextCatalog.GetString("Enable Source Analysis");
                menu.Add(new CodeFixMenuEntry(enableLabel, enableAction));
                first = false;
            }

            return(menu);

            void enableAction() => AnalysisOptions.AnalysisEnabled.Value = true;
        }
コード例 #12
0
        static void AddConfigurationMenuEntry(Diagnostic diag, CodeDiagnosticDescriptor descriptor, Microsoft.CodeAnalysis.CodeFixes.CodeFix fix, CodeFixMenu configureMenu)
        {
            var configurable = !DescriptorHasTag(diag.Descriptor, WellKnownDiagnosticTags.NotConfigurable);

            if (descriptor != null && configurable)
            {
                var optionsMenuItem = new CodeFixMenuEntry(GettextCatalog.GetString("_Configure Rule \u2018{0}\u2019", diag.Descriptor.Title),
                                                           delegate {
                    IdeApp.Workbench.ShowGlobalPreferencesDialog(null, "C#", dialog => {
                        var panel = dialog.GetPanel <CodeIssuePanel> ("C#");
                        if (panel == null)
                        {
                            return;
                        }
                        var title = GettextCatalog.GetString("{0} ({1})", fix.PrimaryDiagnostic.Descriptor.Title, fix.PrimaryDiagnostic.Descriptor.Id);
                        panel.Widget.SelectCodeIssue(title);
                    });
                });
                configureMenu.Add(optionsMenuItem);
            }
        }
コード例 #13
0
        public static async Task <CodeFixMenu> CreateFixMenu(TextEditor editor, CodeActionContainer fixes, CancellationToken cancellationToken = default(CancellationToken))
        {
            var menu = new CodeFixMenu();

            if (editor.DocumentContext.AnalysisDocument == null)
            {
                return(menu);
            }

            int mnemonic = 1;

            var suppressLabel = GettextCatalog.GetString("_Suppress");
            var suppressMenu  = new CodeFixMenu(suppressLabel);

            var fixAllLabel = GettextCatalog.GetString("_Fix all");
            var fixAllMenu  = new CodeFixMenu(fixAllLabel);

            var configureLabel = GettextCatalog.GetString("_Options");
            var configureMenu  = new CodeFixMenu(configureLabel);
            var fixAllTasks    = new List <Task <CodeAction> > ();

            foreach (var cfa in fixes.CodeFixActions)
            {
                var state  = cfa.FixAllState;
                var scopes = cfa.SupportedScopes;

                foreach (var fix in cfa.Fixes)
                {
                    var diag = fix.PrimaryDiagnostic;

                    if (options.TryGetDiagnosticDescriptor(diag.Id, out var descriptor) && !descriptor.GetIsEnabled(diag.Descriptor))
                    {
                        continue;
                    }

                    bool isSuppress = fix.Action is TopLevelSuppressionCodeAction;

                    if (isSuppress)
                    {
                        AddFixMenuItem(editor, suppressMenu, ref mnemonic, fix.Action);
                        continue;
                    }

                    AddFixMenuItem(editor, menu, ref mnemonic, fix.Action);

                    var configurable = !DescriptorHasTag(diag.Descriptor, WellKnownDiagnosticTags.NotConfigurable);
                    if (descriptor != null && configurable)
                    {
                        var optionsMenuItem = new CodeFixMenuEntry(GettextCatalog.GetString("_Configure Rule \u2018{0}\u2019", diag.Descriptor.Title),
                                                                   delegate {
                            IdeApp.Workbench.ShowGlobalPreferencesDialog(null, "C#", dialog => {
                                var panel = dialog.GetPanel <CodeIssuePanel> ("C#");
                                if (panel == null)
                                {
                                    return;
                                }
                                panel.Widget.SelectCodeIssue(fix.PrimaryDiagnostic.Descriptor.Id);
                            });
                        });
                        configureMenu.Add(optionsMenuItem);
                    }

                    if (!scopes.Contains(FixAllScope.Document))
                    {
                        continue;
                    }

                    // FIXME: No global undo yet to support fixall in project/solution
                    var fixState = state.WithScopeAndEquivalenceKey(FixAllScope.Document, fix.Action.EquivalenceKey);

                    var provider = state.FixAllProvider;
                    if (provider == null)
                    {
                        continue;
                    }

                    // FIXME: Use a real progress tracker.
                    var fixAll = Task.Run(() => provider.GetFixAsync(fixState.CreateFixAllContext(new RoslynProgressTracker(), cancellationToken)));
                    fixAllTasks.Add(fixAll);
                }
            }

            var fixAllActions = await Task.WhenAll(fixAllTasks);

            foreach (var fixAllAction in fixAllActions)
            {
                AddFixMenuItem(editor, fixAllMenu, ref mnemonic, fixAllAction);
            }

            bool first = true;

            foreach (var refactoring in fixes.CodeRefactoringActions)
            {
                if (options.TryGetRefactoringDescriptor(refactoring.GetType(), out var descriptor) && !descriptor.IsEnabled)
                {
                    continue;
                }

                if (first)
                {
                    if (menu.Items.Count > 0)
                    {
                        menu.Add(CodeFixMenuEntry.Separator);
                    }
                    first = false;
                }

                foreach (var action in refactoring.Actions)
                {
                    AddFixMenuItem(editor, menu, ref mnemonic, action);
                }
            }

            first = true;

            if (fixAllMenu.Items.Count != 0)
            {
                if (first)
                {
                    menu.Add(CodeFixMenuEntry.Separator);
                }
                menu.Add(fixAllMenu);
                first = false;
            }
            if (suppressMenu.Items.Count != 0)
            {
                if (first)
                {
                    menu.Add(CodeFixMenuEntry.Separator);
                }
                menu.Add(suppressMenu);
                first = false;
            }
            if (configureMenu.Items.Count != 0)
            {
                if (first)
                {
                    menu.Add(CodeFixMenuEntry.Separator);
                }
                menu.Add(configureMenu);
                first = false;
            }
            return(menu);
        }
コード例 #14
0
        public static CodeFixMenu CreateFixMenu(TextEditor editor, CodeActionContainer fixes, CancellationToken cancellationToken = default(CancellationToken))
        {
            var menu = new CodeFixMenu();

            if (editor.DocumentContext.AnalysisDocument == null)
            {
                return(menu);
            }

            int mnemonic = 1;

            var suppressLabel = GettextCatalog.GetString("_Suppress");
            var suppressMenu  = new CodeFixMenu(suppressLabel);

            var fixAllLabel = GettextCatalog.GetString("_Fix all");
            var fixAllMenu  = new CodeFixMenu(fixAllLabel);

            var configureLabel = GettextCatalog.GetString("_Options");
            var configureMenu  = new CodeFixMenu(configureLabel);
            var fixAllTasks    = new List <Task <CodeAction> > ();

            foreach (var cfa in fixes.CodeFixActions)
            {
                var scopes = cfa.SupportedScopes;

                // FIXME: No global undo yet to support fixall in project/solution
                var state = scopes.Contains(FixAllScope.Document) ? cfa.FixAllState : null;

                foreach (var fix in cfa.Fixes)
                {
                    var diag = fix.PrimaryDiagnostic;

                    if (options.TryGetDiagnosticDescriptor(diag.Id, out var descriptor) && !descriptor.GetIsEnabled(diag.Descriptor))
                    {
                        continue;
                    }

                    bool isSuppress = fix.Action is TopLevelSuppressionCodeAction;

                    CodeFixMenu fixMenu;
                    FixAllState fixState;
                    if (isSuppress)
                    {
                        fixMenu  = suppressMenu;
                        fixState = null;
                    }
                    else
                    {
                        fixMenu  = menu;
                        fixState = state;
                        AddConfigurationMenuEntry(diag, descriptor, fix, configureMenu);
                    }

                    AddFixMenuItem(editor, fixMenu, fixAllMenu, ref mnemonic, fix.Action, fixState, cancellationToken);
                }
            }

            bool first = true;

            foreach (var refactoring in fixes.CodeRefactoringActions)
            {
                if (options.TryGetRefactoringDescriptor(refactoring.GetType(), out var descriptor) && !descriptor.IsEnabled)
                {
                    continue;
                }

                if (first)
                {
                    if (menu.Items.Count > 0)
                    {
                        menu.Add(CodeFixMenuEntry.Separator);
                    }
                    first = false;
                }

                foreach (var action in refactoring.Actions)
                {
                    AddFixMenuItem(editor, menu, null, ref mnemonic, action, null, cancellationToken);
                }
            }

            first = true;

            AddMenuWithSeparatorIfNeeded(fixAllMenu, menu, ref first);
            AddMenuWithSeparatorIfNeeded(suppressMenu, menu, ref first);
            AddMenuWithSeparatorIfNeeded(configureMenu, menu, ref first);

            return(menu);
        }