Beispiel #1
0
        public async Task<FirstDiagnosticResult> GetMostSevereFixableDiagnosticAsync(
            Document document, TextSpan range, CancellationToken cancellationToken)
        {
            if (document == null || !document.IsOpen())
            {
                return default;
            }

            using var diagnostics = SharedPools.Default<List<DiagnosticData>>().GetPooledObject();
            using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

            var linkedToken = linkedTokenSource.Token;

            // This flag is used by SuggestedActionsSource to track what solution is was
            // last able to get "full results" for.
            var isFullResult = await _diagnosticService.TryAppendDiagnosticsForSpanAsync(
                document, range, diagnostics.Object, cancellationToken: linkedToken).ConfigureAwait(false);

            var errorDiagnostics = diagnostics.Object.Where(d => d.Severity == DiagnosticSeverity.Error);
            var otherDiagnostics = diagnostics.Object.Where(d => d.Severity != DiagnosticSeverity.Error);

            // Kick off a task that will determine there's an Error Diagnostic with a fixer
            var errorDiagnosticsTask = Task.Run(
                () => GetFirstDiagnosticWithFixAsync(document, errorDiagnostics, range, linkedToken),
                linkedToken);

            // Kick off a task that will determine if any non-Error Diagnostic has a fixer
            var otherDiagnosticsTask = Task.Run(
                () => GetFirstDiagnosticWithFixAsync(document, otherDiagnostics, range, linkedToken),
                linkedToken);

            // If the error diagnostics task happens to complete with a non-null result before
            // the other diagnostics task, we can cancel the other task.
            var diagnostic = await errorDiagnosticsTask.ConfigureAwait(false)
                ?? await otherDiagnosticsTask.ConfigureAwait(false);
            linkedTokenSource.Cancel();

            return new FirstDiagnosticResult(partialResult: !isFullResult,
                                   hasFix: diagnostic != null,
                                   diagnostic: diagnostic);
        }
Beispiel #2
0
        public async Task <FirstDiagnosticResult> GetFirstDiagnosticWithFixAsync(
            Document document, TextSpan range, CancellationToken cancellationToken)
        {
            if (document == null || !document.IsOpen())
            {
                return(default(FirstDiagnosticResult));
            }

            using (var diagnostics = SharedPools.Default <List <DiagnosticData> >().GetPooledObject())
            {
                var fullResult = await _diagnosticService.TryAppendDiagnosticsForSpanAsync(document, range, diagnostics.Object, cancellationToken : cancellationToken).ConfigureAwait(false);

                foreach (var diagnostic in diagnostics.Object)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    if (!range.IntersectsWith(diagnostic.TextSpan))
                    {
                        continue;
                    }

                    // REVIEW: 2 possible designs.
                    // 1. find the first fix and then return right away. if the lightbulb is actually expanded, find all fixes for the line synchronously. or
                    // 2. kick off a task that finds all fixes for the given range here but return once we find the first one.
                    // at the same time, let the task to run to finish. if the lightbulb is expanded, we just simply use the task to get all fixes.
                    //
                    // first approach is simpler, so I will implement that first. if the first approach turns out to be not good enough, then
                    // I will try the second approach which will be more complex but quicker
                    var hasFix = await ContainsAnyFix(document, diagnostic, cancellationToken).ConfigureAwait(false);

                    if (hasFix)
                    {
                        return(new FirstDiagnosticResult(!fullResult, hasFix, diagnostic));
                    }
                }

                return(new FirstDiagnosticResult(!fullResult, false, default(DiagnosticData)));
            }
        }