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.TryGetDiagnosticsForSpanAsync(document, range, diagnostics.Object, 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))); } }