Exemple #1
0
            public FloatingQuickFixIconWidget(
                CodeActionEditorExtension codeActionEditorExtension,
                LanguageItemWindow window,
                SourceEditorView sourceEditorView,
                CodeActionContainer fixes,
                Cairo.Point point) : base(Gtk.WindowType.Popup)
            {
                this.ext              = codeActionEditorExtension;
                this.window           = window;
                this.sourceEditorView = sourceEditorView;
                this.fixes            = fixes;
                this.point            = point;
                this.Decorated        = false;
                this.Events          |= EventMask.ButtonPressMask | EventMask.LeaveNotifyMask | EventMask.EnterNotifyMask;
                TypeHint              = Gdk.WindowTypeHint.Utility;
                var fr = new Gtk.HBox();

                fr.BorderWidth = 2;
                var view = new ImageView(SmartTagMarginMarker.GetIconId(fixes.GetSmartTagSeverity()), Gtk.IconSize.Menu);

                fr.PackStart(view, false, false, 0);
                fr.PackEnd(new RectangleMarker(), false, false, 0);
                Add(fr);
                ext.FixesMenuClosed += Ext_FixesMenuClosed;

                ShowAll();
            }
Exemple #2
0
        static void AssertCodeFixes(CodeActionContainer fixes, ExpectedCodeFixes expected)
        {
            var fixActions = fixes.CodeFixActions.SelectMany(x => x.Fixes).ToArray();

            Assert.AreEqual(expected.CodeFixData.Length, fixActions.Length);
            for (int j = 0; j < expected.CodeFixData.Length; ++j)
            {
                Assert.AreEqual(expected.CodeFixData [j].Message, fixActions [j].Action.Message);
            }

            var fixRefactorings = fixes.CodeRefactoringActions.SelectMany(x => x.Actions).ToArray();

            Assert.AreEqual(expected.CodeRefactoringData.Length, fixRefactorings.Length);
            for (int j = 0; j < expected.CodeRefactoringData.Length; ++j)
            {
                Assert.AreEqual(expected.CodeRefactoringData [j].Message, fixRefactorings [j].Message);
            }
        }
		void CreateSmartTag (CodeActionContainer fixes, int offset)
		{
			if (!AnalysisOptions.EnableFancyFeatures || fixes.IsEmpty) {
				RemoveWidget ();
				return;
			}
			var editor = Editor;
			if (editor == null) {
				RemoveWidget ();
				return;
			}
			if (DocumentContext.ParsedDocument == null || DocumentContext.ParsedDocument.IsInvalid) {
				RemoveWidget ();
				return;
			}

//			var container = editor.Parent;
//			if (container == null) {
//				RemoveWidget ();
//				return;
//			}
			bool first = true;
			var smartTagLocBegin = offset;
			foreach (var fix in fixes.CodeFixActions.Concat (fixes.CodeRefactoringActions)) {
				var textSpan = fix.ValidSegment;
				if (textSpan.IsEmpty)
					continue;
				if (first || offset < textSpan.Start) {
					smartTagLocBegin = textSpan.Start;
				}
				first = false;
			}
//			if (smartTagLocBegin.Line != loc.Line)
//				smartTagLocBegin = new DocumentLocation (loc.Line, 1);
			// got no fix location -> try to search word start
//			if (first) {
//				int offset = document.Editor.LocationToOffset (smartTagLocBegin);
//				while (offset > 0) {
//					char ch = document.Editor.GetCharAt (offset - 1);
//					if (!char.IsLetterOrDigit (ch) && ch != '_')
//						break;
//					offset--;
//				}
//				smartTagLocBegin = document.Editor.OffsetToLocation (offset);
//			}

			if (currentSmartTag != null && currentSmartTagBegin == smartTagLocBegin) {
				return;
			}
			RemoveWidget ();
			currentSmartTagBegin = smartTagLocBegin;
			var realLoc = Editor.OffsetToLocation (smartTagLocBegin);

			currentSmartTag = TextMarkerFactory.CreateSmartTagMarker (Editor, smartTagLocBegin, realLoc);
			currentSmartTag.CancelPopup += CurrentSmartTag_CancelPopup;
			currentSmartTag.ShowPopup += CurrentSmartTag_ShowPopup;
			currentSmartTag.Tag = fixes;
			currentSmartTag.IsVisible = fixes.CodeFixActions.Count > 0;
			editor.AddMarker (currentSmartTag);
		}
		void HandleCaretPositionChanged (object sender, EventArgs e)
		{
			if (Editor.IsInAtomicUndo)
				return;
			CancelQuickFixTimer ();
			if (AnalysisOptions.EnableFancyFeatures && DocumentContext.ParsedDocument != null && !Debugger.DebuggingService.IsDebugging) {
				var token = quickFixCancellationTokenSource.Token;
				var curOffset = Editor.CaretOffset;
				if (HasCurrentFixes) {
					foreach (var fix in GetCurrentFixes ().AllValidCodeActions) {
						if (!fix.ValidSegment.Contains (curOffset)) {
							RemoveWidget ();
							break;
						}
					}
				}

				var loc = Editor.CaretOffset;
				var ad = DocumentContext.AnalysisDocument;
				if (ad == null) {
					return;
				}

				TextSpan span;

				if (Editor.IsSomethingSelected) {
					var selectionRange = Editor.SelectionRange;
					span = selectionRange.Offset >= 0 ? TextSpan.FromBounds (selectionRange.Offset, selectionRange.EndOffset) : TextSpan.FromBounds (loc, loc);
				} else {
					span = TextSpan.FromBounds (loc, loc);
				}

				var diagnosticsAtCaret =
					Editor.GetTextSegmentMarkersAt (Editor.CaretOffset)
					      .OfType<IGenericTextSegmentMarker> ()
					      .Select (rm => rm.Tag)
					      .OfType<DiagnosticResult> ()
					      .Select (dr => dr.Diagnostic)
					      .ToList ();
				
				var errorList = Editor
					.GetTextSegmentMarkersAt (Editor.CaretOffset)
					.OfType<IErrorMarker> ()
					.Where (rm => !string.IsNullOrEmpty (rm.Error.Id)).ToList ();
				int editorLength = Editor.Length;

				smartTagTask = Task.Run (async delegate {
					try {
						var codeIssueFixes = new List<ValidCodeDiagnosticAction> ();
						var diagnosticIds = diagnosticsAtCaret.Select (diagnostic => diagnostic.Id).Concat (errorList.Select (rm => rm.Error.Id)).ToList ();
						if (codeFixes == null) {
							codeFixes = (await CodeRefactoringService.GetCodeFixesAsync (DocumentContext, CodeRefactoringService.MimeTypeToLanguage (Editor.MimeType), token).ConfigureAwait (false)).ToList ();
						}
						foreach (var cfp in codeFixes) {
							if (token.IsCancellationRequested)
								return CodeActionContainer.Empty;
							var provider = cfp.GetCodeFixProvider ();
							if (!provider.FixableDiagnosticIds.Any (diagnosticIds.Contains))
								continue;
							try {
								var groupedDiagnostics = diagnosticsAtCaret
									.Concat (errorList.Select (em => em.Error.Tag)
									.OfType<Diagnostic> ())
									.GroupBy (d => d.Location.SourceSpan);
								foreach (var g in groupedDiagnostics) {
									if (token.IsCancellationRequested)
										return CodeActionContainer.Empty;
									var diagnosticSpan = g.Key;

									var validDiagnostics = g.Where (d => provider.FixableDiagnosticIds.Contains (d.Id)).ToImmutableArray ();
									if (validDiagnostics.Length == 0)
										continue;
									await provider.RegisterCodeFixesAsync (new CodeFixContext (ad, diagnosticSpan, validDiagnostics, (ca, d) => codeIssueFixes.Add (new ValidCodeDiagnosticAction (cfp, ca, validDiagnostics, diagnosticSpan)), token));

									// TODO: Is that right ? Currently it doesn't really make sense to run one code fix provider on several overlapping diagnostics at the same location
									//       However the generate constructor one has that case and if I run it twice the same code action is generated twice. So there is a dupe check problem there.
									// Work around for now is to only take the first diagnostic batch.
									break;
								}
							} catch (OperationCanceledException) {
								return CodeActionContainer.Empty;
							} catch (AggregateException ae) {
								ae.Flatten ().Handle (aex => aex is OperationCanceledException);
								return CodeActionContainer.Empty;
							} catch (Exception ex) {
								LoggingService.LogError ("Error while getting refactorings from code fix provider " + cfp.Name, ex);
								continue;
							}
						}
						var codeActions = new List<ValidCodeAction> ();
						foreach (var action in await CodeRefactoringService.GetValidActionsAsync (Editor, DocumentContext, span, token).ConfigureAwait (false)) {
							codeActions.Add (action);
						}
						var codeActionContainer = new CodeActionContainer (codeIssueFixes, codeActions, diagnosticsAtCaret);
						Application.Invoke (delegate {
							if (token.IsCancellationRequested)
								return;
							if (codeActionContainer.IsEmpty) {
								RemoveWidget ();
								return;
							}
							CreateSmartTag (codeActionContainer, loc);
						});
						return codeActionContainer;

					} catch (AggregateException ae) {
						ae.Flatten ().Handle (aex => aex is OperationCanceledException);
						return CodeActionContainer.Empty;
					} catch (OperationCanceledException) {
						return CodeActionContainer.Empty;
					} catch (TargetInvocationException ex) {
						if (ex.InnerException is OperationCanceledException)
							return CodeActionContainer.Empty;
						throw;
					}

				}, token);
			} else {
				RemoveWidget ();
			}
		}
Exemple #5
0
        static CommandInfoSet CreateFixMenu(TextEditor editor, DocumentContext ctx, SemanticModel semanticModel, CodeActionContainer container)
        {
            if (editor == null)
            {
                throw new ArgumentNullException(nameof(editor));
            }
            if (ctx == null)
            {
                throw new ArgumentNullException(nameof(ctx));
            }
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }
            var result = new CommandInfoSet();

            result.Text = GettextCatalog.GetString("Fix");
            foreach (var diagnostic in container.CodeFixActions)
            {
                var info = new CommandInfo(diagnostic.CodeAction.Title);
                result.CommandInfos.Add(info, new Action(async() => await new CodeActionEditorExtension.ContextActionRunner(diagnostic.CodeAction, editor, ctx).Run()));
            }
            bool firstDiagnosticOption = result.CommandInfos.Count != 0;

            var warningsAtCaret = semanticModel
                                  .GetDiagnostics(new TextSpan(editor.CaretOffset, 0))
                                  .Where(diag => diag.Severity == DiagnosticSeverity.Warning).ToList();

            foreach (var warning in warningsAtCaret)
            {
                if (firstDiagnosticOption)
                {
                    result.CommandInfos.AddSeparator();
                    firstDiagnosticOption = false;
                }

                var label   = GettextCatalog.GetString("_Options for \"{0}\"", warning.Descriptor.Title);
                var subMenu = new CommandInfoSet();
                subMenu.Text = label;

                var info = new CommandInfo(GettextCatalog.GetString("_Suppress with #pragma"));
                subMenu.CommandInfos.Add(info, new Action(async delegate {
                    var fixes = await CSharpSuppressionFixProvider.Instance.GetSuppressionsAsync(ctx.AnalysisDocument, new TextSpan(editor.CaretOffset, 0), new [] { warning }, default(CancellationToken)).ConfigureAwait(false);
                    foreach (var f in fixes)
                    {
                        CodeDiagnosticDescriptor.RunAction(ctx, f.Action, default(CancellationToken));
                    }
                }));

                result.CommandInfos.Add(subMenu);
            }

            foreach (var fix in container.DiagnosticsAtCaret)
            {
                var inspector = BuiltInCodeDiagnosticProvider.GetCodeDiagnosticDescriptor(fix.Id);
                if (inspector == null)
                {
                    continue;
                }

                if (firstDiagnosticOption)
                {
                    result.CommandInfos.AddSeparator();
                    firstDiagnosticOption = false;
                }

                var label   = GettextCatalog.GetString("_Options for \"{0}\"", fix.GetMessage());
                var subMenu = new CommandInfoSet();
                subMenu.Text = label;

                //				if (inspector.CanSuppressWithAttribute) {
                //					var menuItem = new FixMenuEntry (GettextCatalog.GetString ("_Suppress with attribute"),
                //						delegate {
                //
                //							inspector.SuppressWithAttribute (Editor, DocumentContext, GetTextSpan (fix.Item2));
                //						});
                //					subMenu.Add (menuItem);
                //				}

                if (inspector.CanDisableWithPragma)
                {
                    var info = new CommandInfo(GettextCatalog.GetString("_Suppress with #pragma"));
                    subMenu.CommandInfos.Add(info, new Action(() => inspector.DisableWithPragma(editor, ctx, fix)));

                    info = new CommandInfo(GettextCatalog.GetString("_Suppress with file"));
                    subMenu.CommandInfos.Add(info, new Action(() => inspector.DisableWithFile(editor, ctx, fix)));
                }

                var configInfo = new CommandInfo(GettextCatalog.GetString("_Configure Rule"));
                subMenu.CommandInfos.Add(configInfo, new Action(() => {
                    IdeApp.Workbench.ShowGlobalPreferencesDialog(null, "C#", dialog => {
                        var panel = dialog.GetPanel <CodeIssuePanel> ("C#");
                        if (panel == null)
                        {
                            return;
                        }
                        panel.Widget.SelectCodeIssue(inspector.IdString);
                    });
                }));

                foreach (var fix2 in container.CodeFixActions)
                {
                    var provider = fix2.Diagnostic.GetCodeFixProvider().GetFixAllProvider();
                    if (provider == null)
                    {
                        continue;
                    }
                    if (!provider.GetSupportedFixAllScopes().Contains(FixAllScope.Document))
                    {
                        continue;
                    }
                    var subMenu2 = new CommandInfoSet();
                    subMenu2.Text = GettextCatalog.GetString("Fix all");
                    var diagnosticAnalyzer = fix2.Diagnostic.GetCodeDiagnosticDescriptor(LanguageNames.CSharp).GetProvider();
                    if (!diagnosticAnalyzer.SupportedDiagnostics.Contains(fix.Descriptor))
                    {
                        continue;
                    }

                    var info = new CommandInfo(GettextCatalog.GetString("In _Document"));
                    subMenu2.CommandInfos.Add(info, new Action(async delegate {
                        var fixAllDiagnosticProvider = new CodeActionEditorExtension.FixAllDiagnosticProvider(diagnosticAnalyzer.SupportedDiagnostics.Select(d => d.Id).ToImmutableHashSet(), async(Microsoft.CodeAnalysis.Document doc, ImmutableHashSet <string> diagnostics, CancellationToken token) => {
                            var model = await doc.GetSemanticModelAsync(token);
                            var compilationWithAnalyzer = model.Compilation.WithAnalyzers(new [] { diagnosticAnalyzer }.ToImmutableArray(), null, token);

                            return(await compilationWithAnalyzer.GetAnalyzerSemanticDiagnosticsAsync(model, null, token));
                        }, (arg1, arg2, arg3, arg4) => {
                            return(Task.FromResult((IEnumerable <Diagnostic>) new Diagnostic [] { }));
                        });
                        var ctx2 = new FixAllContext(
                            ctx.AnalysisDocument,
                            fix2.Diagnostic.GetCodeFixProvider(),
                            FixAllScope.Document,
                            fix2.CodeAction.EquivalenceKey,
                            diagnosticAnalyzer.SupportedDiagnostics.Select(d => d.Id),
                            fixAllDiagnosticProvider,
                            default(CancellationToken)
                            );
                        var fixAll = await provider.GetFixAsync(ctx2);
                        using (var undo = editor.OpenUndoGroup()) {
                            CodeDiagnosticDescriptor.RunAction(ctx, fixAll, default(CancellationToken));
                        }
                    }));
                    subMenu.CommandInfos.Add(subMenu2);
                }
                result.CommandInfos.Add(subMenu);
            }

            return(result);
        }
		static CommandInfoSet CreateFixMenu (TextEditor editor, DocumentContext ctx, CodeActionContainer container)
		{
			if (editor == null)
				throw new ArgumentNullException ("editor");
			if (ctx == null)
				throw new ArgumentNullException ("ctx");
			if (container == null)
				throw new ArgumentNullException ("container");
			var result = new CommandInfoSet ();
			result.Text = GettextCatalog.GetString ("Fix");
			foreach (var diagnostic in container.CodeFixActions) {
				var info = new CommandInfo (diagnostic.CodeAction.Title);
				result.CommandInfos.Add (info, new Action (new CodeActionEditorExtension.ContextActionRunner (diagnostic.CodeAction, editor, ctx).Run));
			}
			if (result.CommandInfos.Count == 0)
				return result;
			bool firstDiagnosticOption = true;
			foreach (var fix in container.DiagnosticsAtCaret) {

				var inspector = BuiltInCodeDiagnosticProvider.GetCodeDiagnosticDescriptor (fix.Id);
				if (inspector == null)
					continue;

				if (firstDiagnosticOption) {
					result.CommandInfos.AddSeparator ();
					firstDiagnosticOption = false;
				}

				var label = GettextCatalog.GetString ("_Options for \"{0}\"", fix.GetMessage ());
				var subMenu = new CommandInfoSet ();
				subMenu.Text = label;

//				if (inspector.CanSuppressWithAttribute) {
//					var menuItem = new FixMenuEntry (GettextCatalog.GetString ("_Suppress with attribute"),
//						delegate {
//							
//							inspector.SuppressWithAttribute (Editor, DocumentContext, GetTextSpan (fix.Item2)); 
//						});
//					subMenu.Add (menuItem);
//				}

				if (inspector.CanDisableWithPragma) {
					var info = new CommandInfo (GettextCatalog.GetString ("_Suppress with #pragma"));
					subMenu.CommandInfos.Add (info, new Action (() => inspector.DisableWithPragma (editor, ctx, fix)));

					info = new CommandInfo (GettextCatalog.GetString ("_Suppress with file"));
					subMenu.CommandInfos.Add (info, new Action (() => inspector.DisableWithFile (editor, ctx, fix)));
				}

				var configInfo = new CommandInfo (GettextCatalog.GetString ("_Configure Rule"));
				subMenu.CommandInfos.Add (configInfo, new Action (() => {
					IdeApp.Workbench.ShowGlobalPreferencesDialog (null, "C#", dialog => {
						var panel = dialog.GetPanel<CodeIssuePanel> ("C#");
						if (panel == null)
							return;
						panel.Widget.SelectCodeIssue (inspector.IdString);
					});
				}));

				foreach (var fix2 in container.CodeFixActions) {

					var provider = fix2.Diagnostic.GetCodeFixProvider ().GetFixAllProvider ();
					if (provider == null)
						continue;
					if (!provider.GetSupportedFixAllScopes ().Contains (FixAllScope.Document))
						continue;
					var subMenu2 = new CommandInfoSet ();
					subMenu2.Text = GettextCatalog.GetString ("Fix all");
					var diagnosticAnalyzer = fix2.Diagnostic.GetCodeDiagnosticDescriptor (LanguageNames.CSharp).GetProvider ();
					if (!diagnosticAnalyzer.SupportedDiagnostics.Contains (fix.Descriptor))
						continue;

					var info = new CommandInfo (GettextCatalog.GetString ("In _Document"));
					subMenu2.CommandInfos.Add (info, new Action (async delegate {
						
						var fixAllDiagnosticProvider = new CodeActionEditorExtension.FixAllDiagnosticProvider (diagnosticAnalyzer.SupportedDiagnostics.Select (d => d.Id).ToImmutableHashSet (), async (Microsoft.CodeAnalysis.Document doc, ImmutableHashSet<string> diagnostics, CancellationToken token) => {

							var model = await doc.GetSemanticModelAsync (token);
							var compilationWithAnalyzer = model.Compilation.WithAnalyzers (new [] { diagnosticAnalyzer }.ToImmutableArray (), null, token);

							return await compilationWithAnalyzer.GetAnalyzerSemanticDiagnosticsAsync (model, null, token);
						}, (arg1, arg2, arg3, arg4) => {
							return Task.FromResult ((IEnumerable<Diagnostic>)new Diagnostic[] { });
						});
						var ctx2 = new FixAllContext (
							ctx.AnalysisDocument,
							fix2.Diagnostic.GetCodeFixProvider (),
							FixAllScope.Document,
							fix2.CodeAction.EquivalenceKey,
							diagnosticAnalyzer.SupportedDiagnostics.Select (d => d.Id),
							fixAllDiagnosticProvider,
							default (CancellationToken)
						);
						var fixAll = await provider.GetFixAsync (ctx2);
						using (var undo = editor.OpenUndoGroup ()) {
							CodeDiagnosticDescriptor.RunAction (ctx, fixAll, default (CancellationToken));
						}
					}));
					subMenu.CommandInfos.Add (subMenu2);
				}
				result.CommandInfos.Add (subMenu);
			}

			return result;
		}