コード例 #1
0
        void HandleCaretPositionChanged(object sender, EventArgs e)
        {
            if (Editor.IsInAtomicUndo)
            {
                return;
            }
            CancelQuickFixTimer();
            if (AnalysisOptions.EnableFancyFeatures && DocumentContext.ParsedDocument != null)
            {
                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();
            }
        }
コード例 #2
0
        internal Task <CodeActionContainer> GetCurrentFixesAsync(CancellationToken cancellationToken)
        {
            var loc = Editor.CaretOffset;
            var ad  = DocumentContext.AnalysisDocument;

            if (ad == null)
            {
                return(Task.FromResult(CodeActionContainer.Empty));
            }
            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 rExt      = Editor.GetContent <ResultsEditorExtension> ();
            var errorList = Editor
                            .GetTextSegmentMarkersAt(Editor.CaretOffset)
                            .OfType <IErrorMarker> ()
                            .Where(rm => !string.IsNullOrEmpty(rm.Error.Id)).ToList();

            return(Task.Run(async delegate {
                try {
                    var result = await CodeDiagnosticRunner.Check(new AnalysisDocument(Editor, DocumentContext), cancellationToken).ConfigureAwait(false);
                    var diagnosticsAtCaret = result.OfType <DiagnosticResult> ().Where(d => d.Region.Contains(loc)).Select(d => d.Diagnostic).ToList();

                    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), cancellationToken).ConfigureAwait(false)).ToList();
                    }
                    var root = await ad.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
                    foreach (var cfp in codeFixes)
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            return CodeActionContainer.Empty;
                        }
                        var provider = cfp.GetCodeFixProvider();
                        if (!provider.FixableDiagnosticIds.Any(diagnosticIds.Contains))
                        {
                            continue;
                        }

                        // These two delegates were factored out, as using them as lambdas in the inner loop creates more captures than declaring them here.
                        Func <Diagnostic, bool> providerIdsContain = d => provider.FixableDiagnosticIds.Contains(d.Id);
                        Action <Microsoft.CodeAnalysis.CodeActions.CodeAction, ImmutableArray <Diagnostic> > codeFixRegistration = (ca, d) => codeIssueFixes.Add(new ValidCodeDiagnosticAction(cfp, ca, d, d [0].Location.SourceSpan));
                        try {
                            var groupedDiagnostics = diagnosticsAtCaret
                                                     .Concat(errorList.Select(em => em.Error.Tag)
                                                             .OfType <Diagnostic> ())
                                                     .GroupBy(d => d.Location.SourceSpan);
                            foreach (var g in groupedDiagnostics)
                            {
                                if (cancellationToken.IsCancellationRequested)
                                {
                                    return CodeActionContainer.Empty;
                                }
                                var diagnosticSpan = g.Key;
                                var validDiagnostics = g.Where(providerIdsContain).ToImmutableArray();
                                if (validDiagnostics.Length == 0)
                                {
                                    continue;
                                }
                                if (diagnosticSpan.Start < 0 || diagnosticSpan.End > root.Span.End)
                                {
                                    continue;
                                }
                                await provider.RegisterCodeFixesAsync(new CodeFixContext(ad, diagnosticSpan, validDiagnostics, codeFixRegistration, cancellationToken)).ConfigureAwait(false);

                                // 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, cancellationToken).ConfigureAwait(false))
                    {
                        codeActions.Add(action);
                    }
                    if (cancellationToken.IsCancellationRequested)
                    {
                        return CodeActionContainer.Empty;
                    }

                    var codeActionContainer = new CodeActionContainer(codeIssueFixes, codeActions, diagnosticsAtCaret);
                    Application.Invoke((o, args) => {
                        if (cancellationToken.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;
                }
            }, cancellationToken));
        }