Skip to content

Commit 854d84d

Browse files
authored
Merge pull request #74862 from dibarbet/fix_mas_pdb
Fix error closing source link documents in VSCode
2 parents d908128 + 75a501c commit 854d84d

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ protected static async Task GenerateFileAndVerifyAsync(
155155

156156
var masWorkspace = service.TryGetWorkspace();
157157

158+
using var fileStream = File.OpenRead(file.FilePath);
159+
var sourceText = SourceText.From(fileStream);
160+
var text = SourceText.From(File.ReadAllText(file.FilePath));
161+
162+
var pdbService = (PdbSourceDocumentMetadataAsSourceFileProvider)workspace.ExportProvider.GetExportedValues<IMetadataAsSourceFileProvider>().Single(s => s is PdbSourceDocumentMetadataAsSourceFileProvider);
163+
164+
var documentInfo = pdbService.GetTestAccessor().Documents[file.FilePath];
165+
masWorkspace!.OnDocumentAdded(documentInfo.DocumentInfo);
158166
var document = masWorkspace!.CurrentSolution.Projects.First().Documents.First(d => d.FilePath == file.FilePath);
159167

160168
// Mapping the project from the generated document should map back to the original project
@@ -330,4 +338,15 @@ protected static string GetPdbPath(string path)
330338
{
331339
return Path.Combine(path, "reference.pdb");
332340
}
341+
342+
private class StaticSourceTextContainer(SourceText sourceText) : SourceTextContainer
343+
{
344+
public override SourceText CurrentText => sourceText;
345+
346+
public override event EventHandler<TextChangeEventArgs> TextChanged
347+
{
348+
add { }
349+
remove { }
350+
}
351+
}
333352
}

src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -244,15 +244,19 @@ internal sealed class PdbSourceDocumentMetadataAsSourceFileProvider(
244244
return null;
245245

246246
var symbolId = SymbolKey.Create(symbol, cancellationToken);
247-
var navigateProject = metadataWorkspace.CurrentSolution.GetRequiredProject(projectId);
248247

249-
var documentInfos = CreateDocumentInfos(sourceFileInfos, encoding, navigateProject.Id, sourceWorkspace, sourceProject);
248+
// Get a view of the solution with the document added, but do not actually update the workspace.
249+
// TryAddDocumentToWorkspace is responsible for actually updating the solution with the new document(s).
250+
// We just need a view with the document added so we can find the right location in the generated source.
251+
var pendingSolution = metadataWorkspace.CurrentSolution;
252+
var documentInfos = CreateDocumentInfos(sourceFileInfos, encoding, projectId, sourceWorkspace, sourceProject);
250253
if (documentInfos.Length > 0)
251254
{
252-
metadataWorkspace.OnDocumentsAdded(documentInfos);
253-
navigateProject = metadataWorkspace.CurrentSolution.GetRequiredProject(projectId);
255+
pendingSolution = pendingSolution.AddDocuments(documentInfos);
254256
}
255257

258+
var navigateProject = pendingSolution.GetRequiredProject(projectId);
259+
256260
// If MetadataAsSourceHelpers.GetLocationInGeneratedSourceAsync can't find the actual document to navigate to, it will fall back
257261
// to the document passed in, which we just use the first document for.
258262
// TODO: Support results from multiple source files: https://github.com/dotnet/roslyn/issues/55834
@@ -319,20 +323,22 @@ private ImmutableArray<DocumentInfo> CreateDocumentInfos(
319323
}
320324

321325
// If a document has multiple symbols then we might already know about it
322-
if (_fileToDocumentInfoMap.ContainsKey(info.FilePath))
326+
if (_fileToDocumentInfoMap.TryGetValue(info.FilePath, out var sourceDocumentInfo))
323327
{
328+
documents.Add(sourceDocumentInfo.DocumentInfo);
324329
continue;
325330
}
326331

327332
var documentId = DocumentId.CreateNewId(projectId);
328333

329-
documents.Add(DocumentInfo.Create(
334+
var documentInfo = DocumentInfo.Create(
330335
documentId,
331336
name: Path.GetFileName(info.FilePath),
332337
loader: info.Loader,
333338
filePath: info.FilePath,
334339
isGenerated: true)
335-
.WithDesignTimeOnly(true));
340+
.WithDesignTimeOnly(true);
341+
documents.Add(documentInfo);
336342

337343
// If we successfully got something from SourceLink for this project then its nice to wait a bit longer
338344
// if the user performs subsequent navigation
@@ -342,7 +348,7 @@ private ImmutableArray<DocumentInfo> CreateDocumentInfos(
342348
}
343349

344350
// In order to open documents in VS we need to understand the link from temp file to document and its encoding etc.
345-
_fileToDocumentInfoMap[info.FilePath] = new(documentId, encoding, info.ChecksumAlgorithm, sourceProject.Id, sourceWorkspace);
351+
_fileToDocumentInfoMap[info.FilePath] = new(documentId, encoding, info.ChecksumAlgorithm, sourceProject.Id, sourceWorkspace, documentInfo);
346352
}
347353

348354
return documents.ToImmutableAndClear();
@@ -359,6 +365,7 @@ public bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, strin
359365
{
360366
if (_fileToDocumentInfoMap.TryGetValue(filePath, out var info))
361367
{
368+
workspace.OnDocumentAdded(info.DocumentInfo);
362369
workspace.OnDocumentOpened(info.DocumentId, sourceTextContainer);
363370
documentId = info.DocumentId;
364371
return true;
@@ -376,6 +383,7 @@ public bool TryRemoveDocumentFromWorkspace(MetadataAsSourceWorkspace workspace,
376383
if (_fileToDocumentInfoMap.TryGetValue(filePath, out var info))
377384
{
378385
workspace.OnDocumentClosed(info.DocumentId, new WorkspaceFileTextLoader(workspace.Services.SolutionServices, filePath, info.Encoding));
386+
workspace.OnDocumentRemoved(info.DocumentId);
379387
return true;
380388
}
381389

@@ -421,8 +429,25 @@ public void CleanupGeneratedFiles(MetadataAsSourceWorkspace workspace)
421429
_sourceLinkEnabledProjects.Clear();
422430
_implementationAssemblyLookupService.Clear();
423431
}
432+
433+
internal TestAccessor GetTestAccessor()
434+
{
435+
return new TestAccessor(this);
436+
}
437+
438+
internal readonly struct TestAccessor
439+
{
440+
private readonly PdbSourceDocumentMetadataAsSourceFileProvider _instance;
441+
442+
internal TestAccessor(PdbSourceDocumentMetadataAsSourceFileProvider instance)
443+
{
444+
_instance = instance;
445+
}
446+
447+
public ImmutableDictionary<string, SourceDocumentInfo> Documents => _instance._fileToDocumentInfoMap.ToImmutableDictionary();
448+
}
424449
}
425450

426451
internal sealed record SourceDocument(string FilePath, SourceHashAlgorithm ChecksumAlgorithm, ImmutableArray<byte> Checksum, byte[]? EmbeddedTextBytes, string? SourceLinkUrl);
427452

428-
internal record struct SourceDocumentInfo(DocumentId DocumentId, Encoding Encoding, SourceHashAlgorithm ChecksumAlgorithm, ProjectId SourceProjectId, Workspace SourceWorkspace);
453+
internal record struct SourceDocumentInfo(DocumentId DocumentId, Encoding Encoding, SourceHashAlgorithm ChecksumAlgorithm, ProjectId SourceProjectId, Workspace SourceWorkspace, DocumentInfo DocumentInfo);

0 commit comments

Comments
 (0)