Skip to content

Commit

Permalink
Add mitigations for SG documents not being present
Browse files Browse the repository at this point in the history
  • Loading branch information
CyrusNajmabadi committed Sep 15, 2023
1 parent b19ba09 commit f6d6c20
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,17 @@ public SerializableDocumentHighlights(DocumentId documentId, ImmutableArray<High
HighlightSpans = highlightSpans;
}

public async ValueTask<DocumentHighlights> RehydrateAsync(Solution solution)
=> new(await solution.GetRequiredDocumentAsync(DocumentId, includeSourceGenerated: true).ConfigureAwait(false), HighlightSpans);
public async ValueTask<DocumentHighlights?> RehydrateAsync(Solution solution, CancellationToken cancellationToken)
{
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(DocumentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return null;

return new(document, HighlightSpans);
}

public static SerializableDocumentHighlights Dehydrate(DocumentHighlights highlights)
=> new(highlights.Document.Id, highlights.HighlightSpans);
Expand Down
10 changes: 8 additions & 2 deletions src/Features/Core/Portable/NavigateTo/RoslynNavigateToItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,14 @@ public RoslynNavigateToItem(
}
else
{
var document = await solution.GetRequiredDocumentAsync(
DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
DocumentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document == null)
return null;

return new NavigateToSearchResult(this, document, activeDocument);
}
}
Expand Down
18 changes: 15 additions & 3 deletions src/Features/Core/Portable/Navigation/INavigableItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,30 @@ public static NavigableDocument FromDocument(Document document)
/// this navigable item. The document is required to exist within the solution, e.g. a case where the
/// navigable item was constructed during a Find Symbols operation on the same solution instance.
/// </summary>
internal ValueTask<Document> GetRequiredDocumentAsync(Solution solution, CancellationToken cancellationToken)
=> solution.GetRequiredDocumentAsync(Id, includeSourceGenerated: IsSourceGeneratedDocument, cancellationToken);
internal async ValueTask<Document?> GetRequiredDocumentAsync(Solution solution, CancellationToken cancellationToken)
{
if (!IsSourceGeneratedDocument)
return solution.GetRequiredDocument(Id);

// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
return await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
Id, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Get the <see cref="SourceText"/> of the <see cref="CodeAnalysis.Document"/> within
/// <paramref name="solution"/> which is referenced by this navigable item. The document is required to
/// exist within the solution, e.g. a case where the navigable item was constructed during a Find Symbols
/// operation on the same solution instance.
/// </summary>
internal async ValueTask<SourceText> GetTextAsync(Solution solution, CancellationToken cancellationToken)
internal async ValueTask<SourceText?> GetTextAsync(Solution solution, CancellationToken cancellationToken)
{
var document = await GetRequiredDocumentAsync(solution, cancellationToken).ConfigureAwait(false);
if (document is null)
return null;

return await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,15 @@ async Task AddMatchingTypesAsync(
cancellationToken.ThrowIfCancellationRequested();

Debug.Assert(infos.Count > 0);
var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);

// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
continue;

var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
cachedModels.Add(semanticModel);

Expand All @@ -276,7 +284,14 @@ async Task AddSourceTypesThatDeriveFromNameAsync(SymbolSet result, string name)
{
cancellationToken.ThrowIfCancellationRequested();

var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
continue;

var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
cachedModels.Add(semanticModel);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,27 @@ public ValueTask OnCompletedAsync(CancellationToken cancellationToken)

public async ValueTask OnFindInDocumentStartedAsync(DocumentId documentId, CancellationToken cancellationToken)
{
var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return;

await progress.OnFindInDocumentStartedAsync(document, cancellationToken).ConfigureAwait(false);
}

public async ValueTask OnFindInDocumentCompletedAsync(DocumentId documentId, CancellationToken cancellationToken)
{
var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return;

await progress.OnFindInDocumentCompletedAsync(document, cancellationToken).ConfigureAwait(false);
}

Expand Down Expand Up @@ -102,10 +116,11 @@ public async ValueTask OnReferenceFoundAsync(
}
}

var referenceLocation = await reference.RehydrateAsync(
solution, cancellationToken).ConfigureAwait(false);
var referenceLocation = await reference.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
if (referenceLocation is null)
return;

await progress.OnReferenceFoundAsync(symbolGroup, symbol, referenceLocation, cancellationToken).ConfigureAwait(false);
await progress.OnReferenceFoundAsync(symbolGroup, symbol, referenceLocation.Value, cancellationToken).ConfigureAwait(false);
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions src/Workspaces/Core/Portable/Remote/RemoteArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,17 @@ public static SerializableReferenceLocation Dehydrate(
referenceLocation.CandidateReason);
}

public async ValueTask<ReferenceLocation> RehydrateAsync(
public async ValueTask<ReferenceLocation?> RehydrateAsync(
Solution solution, CancellationToken cancellationToken)
{
var document = await solution.GetRequiredDocumentAsync(this.Document, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
this.Document, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return null;

var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var aliasSymbol = await RehydrateAliasAsync(solution, cancellationToken).ConfigureAwait(false);
var additionalProperties = this.AdditionalProperties;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ internal partial class SymbolicRenameLocations
serializableLocations.Options,
fallbackOptions,
locations,
implicitLocations,
implicitLocations.WhereNotNull(),
referencedSymbols);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private LightweightRenameLocations(
Options,
FallbackOptions,
Locations,
implicitLocations,
implicitLocations.WhereNotNull(),
referencedSymbols);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ public ValueTask<ImmutableArray<SerializableDocumentHighlights>> GetDocumentHigh
// need to be revisited if we someday support FAR between these languages.
return RunServiceAsync(solutionChecksum, async solution =>
{
var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return ImmutableArray<SerializableDocumentHighlights>.Empty;
var documentsToSearch = await documentIdsToSearch.SelectAsArrayAsync(id => solution.GetDocumentAsync(id, includeSourceGenerated: true, cancellationToken)).ConfigureAwait(false);
var documentsToSearchSet = ImmutableHashSet.CreateRange(documentsToSearch.WhereNotNull());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ public ValueTask<ImmutableArray<InheritanceMarginItem>> GetInheritanceMarginItem
//
// Tracked by https://github.com/dotnet/roslyn/issues/67065.
frozenPartialSemantics = false;
var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return ImmutableArray<InheritanceMarginItem>.Empty;
var service = document.GetRequiredLanguageService<IInheritanceMarginService>();
return await service.GetInheritanceMemberItemsAsync(document, spanToSearch, includeGlobalImports, frozenPartialSemantics, cancellationToken).ConfigureAwait(false);
}, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ public ValueTask<ImmutableArray<SerializableNavigationBarItem>> GetItemsAsync(
{
return RunServiceAsync(solutionChecksum, async solution =>
{
var document = await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
Contract.ThrowIfNull(document);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return ImmutableArray<SerializableNavigationBarItem>.Empty;
if (forceFrozenPartialSemanticsForCrossProcessOperations)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ public ValueTask<ImmutableArray<TaskListItem>> GetTaskListItemsAsync(
{
return RunServiceAsync(solutionChecksum, async solution =>
{
var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
var document = await solution.GetRequiredDocumentIncludingSourceGeneratedAsync(
documentId, throwForMissingSourceGenerated: false, cancellationToken).ConfigureAwait(false);
if (document is null)
return ImmutableArray<TaskListItem>.Empty;
var service = document.GetRequiredLanguageService<ITaskListService>();
return await service.GetTaskListItemsAsync(document, descriptors, cancellationToken).ConfigureAwait(false);
}, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,20 @@ public static ImmutableArray<T> TakeAsArray<T>(this ImmutableArray<T> array, int

return result.ToImmutableAndClear();
}

public static ImmutableArray<T> WhereNotNull<T>(this ImmutableArray<T?> array) where T : struct
{
var count = array.Count(static t => t != null);

using var _ = ArrayBuilder<T>.GetInstance(count, out var result);

foreach (var value in array)
{
if (value != null)
result.Add(value.Value);
}

return result.ToImmutableAndClear();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ErrorReporting;

namespace Microsoft.CodeAnalysis.Shared.Extensions
{
Expand Down Expand Up @@ -48,8 +50,48 @@ public static Document GetRequiredDocument(this Solution solution, DocumentId do
=> solution.GetDocument(documentId) ?? throw CreateDocumentNotFoundException();

#if !CODE_STYLE
public static async ValueTask<Document> GetRequiredDocumentAsync(this Solution solution, DocumentId documentId, bool includeSourceGenerated = false, CancellationToken cancellationToken = default)
=> (await solution.GetDocumentAsync(documentId, includeSourceGenerated, cancellationToken).ConfigureAwait(false)) ?? throw CreateDocumentNotFoundException();
public static async ValueTask<Document?> GetRequiredDocumentIncludingSourceGeneratedAsync(
this Solution solution,
DocumentId documentId,
bool throwForMissingSourceGenerated = true,
CancellationToken cancellationToken = default)
{
var document = await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);

// https://github.com/dotnet/roslyn/issues/69964
//
// Remove this once we solve root cause issue of the hosts disagreeing on source generated documents.
if (document is null)
{
if (documentId.IsSourceGenerated && !throwForMissingSourceGenerated)
{
// Create a crash report so we can better hunt this down.
try
{
throw CreateDocumentNotFoundException();
}
catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical))
{
}

return null;
}

throw CreateDocumentNotFoundException();
}

return document;
}

public static async ValueTask<Document> GetRequiredDocumentAsync(
this Solution solution,
DocumentId documentId,
bool includeSourceGenerated = false,
CancellationToken cancellationToken = default)
{
return await solution.GetDocumentAsync(documentId, includeSourceGenerated, cancellationToken).ConfigureAwait(false) ??
throw CreateDocumentNotFoundException();
}

public static async ValueTask<TextDocument> GetRequiredTextDocumentAsync(this Solution solution, DocumentId documentId, CancellationToken cancellationToken = default)
=> (await solution.GetTextDocumentAsync(documentId, cancellationToken).ConfigureAwait(false)) ?? throw CreateDocumentNotFoundException();
Expand Down

0 comments on commit f6d6c20

Please sign in to comment.