@@ -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
426451internal 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