public async Task <Compilation> GetCompilationAsync(SolutionState solution, CancellationToken cancellationToken) { // Fast path if we've definitely already done this before if (_compilationWithReplacement != null) { return(_compilationWithReplacement); } var underlyingCompilation = await _underlyingTracker.GetCompilationAsync(solution, cancellationToken).ConfigureAwait(false); var underlyingSourceGeneratedDocuments = await _underlyingTracker.GetSourceGeneratedDocumentStatesAsync(solution, cancellationToken).ConfigureAwait(false); underlyingSourceGeneratedDocuments.TryGetState(_replacedGeneratedDocumentState.Id, out var existingState); Compilation newCompilation; var newSyntaxTree = await _replacedGeneratedDocumentState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (existingState != null) { // The generated file still exists in the underlying compilation, but the contents may not match the open file if the open file // is stale. Replace the syntax tree so we have a tree that matches the text. var existingSyntaxTree = await existingState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); newCompilation = underlyingCompilation.ReplaceSyntaxTree(existingSyntaxTree, newSyntaxTree); } else { // The existing output no longer exists in the underlying compilation. This could happen if the user made // an edit which would cause this file to no longer exist, but they're still operating on an open representation // of that file. To ensure that this snapshot is still usable, we'll just add this document back in. This is not a // semantically correct operation, but working on stale snapshots never has that guarantee. newCompilation = underlyingCompilation.AddSyntaxTrees(newSyntaxTree); } Interlocked.CompareExchange(ref _compilationWithReplacement, newCompilation, null); return(_compilationWithReplacement); }