@@ -92,7 +92,7 @@ internal sealed class DecompileWholeAssemblyToProjectMetadataAsSourceFileProvide
9292 if ( _assemblyKeyToProjectInfo . TryGetValue ( assemblyKey , out var existingProjectInfo ) )
9393 {
9494 // The assembly has already been decompiled. Find the document for the requested type.
95- var primaryFilePath = GetPrimaryFilePath ( existingProjectInfo . TempDirectory , topLevelNamedType ) ;
95+ var primaryFilePath = GetPrimaryFilePath ( existingProjectInfo . TempDirectory , topLevelNamedType , assemblyKey . Mvid , Path . GetFileNameWithoutExtension ( assemblyKey . FilePath ) ) ;
9696
9797 if ( _generatedFilenameToInformation . TryGetValue ( primaryFilePath , out var existingDocInfo ) )
9898 {
@@ -431,21 +431,25 @@ private static (ProjectInfo projectInfo, DocumentId primaryDocumentId, IReadOnly
431431 // Read the assembly name and version from the actual resolved PE (after ref->impl and type-forward resolution),
432432 // not from the symbol in the source compilation which may point to a reference assembly.
433433 AssemblyIdentity ? resolvedIdentity = null ;
434- if ( portableExecutableReference . GetMetadata ( ) is AssemblyMetadata assemblyMetadata )
434+ if ( portableExecutableReference . GetMetadata ( ) is not AssemblyMetadata assemblyMetadata )
435435 {
436- // The manifest module (first) contains the assembly definition with name and version.
437- var manifestModule = assemblyMetadata . GetModules ( ) . FirstOrDefault ( ) ;
438- if ( manifestModule is not null )
439- {
440- var reader = manifestModule . GetMetadataReader ( ) ;
441- var asmDef = reader . GetAssemblyDefinition ( ) ;
442- var name = reader . GetString ( asmDef . Name ) ;
443- resolvedIdentity = new AssemblyIdentity ( name , asmDef . Version ) ;
444- }
436+ throw new InvalidOperationException ( "PE metadata reference must be assembly metadata." ) ;
437+ }
438+
439+ // The manifest module (first) contains the assembly definition with name and version.
440+ var manifestModule = assemblyMetadata . GetModules ( ) . FirstOrDefault ( ) ;
441+ if ( manifestModule is not null )
442+ {
443+ var reader = manifestModule . GetMetadataReader ( ) ;
444+ var asmDef = reader . GetAssemblyDefinition ( ) ;
445+ var name = reader . GetString ( asmDef . Name ) ;
446+ resolvedIdentity = new AssemblyIdentity ( name , asmDef . Version ) ;
445447 }
448+
446449 resolvedIdentity ??= topLevelNamedType . ContainingAssembly . Identity ;
447450
448451 var assemblyNameForMetadataAsSourceProjectName = resolvedIdentity . Name ;
452+ var mvid = assemblyMetadata . GetMvid ( ) ;
449453 var assemblyVersion = resolvedIdentity . Version ;
450454
451455 var compilationOptions = services . GetRequiredLanguageService < ICompilationFactoryService > ( fileInfo . LanguageName )
@@ -457,7 +461,7 @@ private static (ProjectInfo projectInfo, DocumentId primaryDocumentId, IReadOnly
457461
458462 // Track which document is the primary one for the requested type.
459463 DocumentId ? primaryDocumentId = null ;
460- var primaryRelativePath = GetRelativePathForType ( topLevelNamedType ) ;
464+ var primaryRelativePath = GetRelativePathForType ( topLevelNamedType , mvid , assemblyNameForMetadataAsSourceProjectName ) ;
461465
462466 if ( decompiledFiles is not null && decompiledFiles . Count > 0 )
463467 {
@@ -538,22 +542,21 @@ private static (ProjectInfo projectInfo, DocumentId primaryDocumentId, IReadOnly
538542 /// <summary>
539543 /// Computes the expected relative path for a type, matching <see cref="WholeAssemblyDecompiler"/>'s naming logic.
540544 /// </summary>
541- private static string GetRelativePathForType ( INamedTypeSymbol topLevelNamedType )
545+ private static string GetRelativePathForType ( INamedTypeSymbol topLevelNamedType , Guid mvid , string assemblyName )
542546 {
543547 var fileName = WholeAssemblyDecompiler . CleanUpFileName ( topLevelNamedType . Name , ".cs" ) ;
544548 var ns = topLevelNamedType . ContainingNamespace ? . ToDisplayString ( ) ?? string . Empty ;
545- if ( string . IsNullOrEmpty ( ns ) )
546- return fileName ;
549+ if ( string . IsNullOrEmpty ( ns ) ) return fileName ;
547550
548551 var dir = WholeAssemblyDecompiler . CleanUpDirectoryName ( ns ) ;
549- return Path . Combine ( dir , fileName ) ;
552+ return Path . Combine ( "decompiled" , assemblyName , mvid . ToString ( ) , dir , fileName ) ;
550553 }
551554
552555 /// <summary>
553556 /// Gets the absolute path for the primary file of a type within the assembly's temp directory.
554557 /// </summary>
555- private static string GetPrimaryFilePath ( string tempDirectory , INamedTypeSymbol topLevelNamedType )
556- => Path . Combine ( tempDirectory , GetRelativePathForType ( topLevelNamedType ) ) ;
558+ private static string GetPrimaryFilePath ( string tempDirectory , INamedTypeSymbol topLevelNamedType , Guid mvid , string assemblyName )
559+ => Path . Combine ( tempDirectory , GetRelativePathForType ( topLevelNamedType , mvid , assemblyName ) ) ;
557560
558561 private ( PortableExecutableReference ? metadataReference , string ? assemblyLocation , bool isReferenceAssembly ) GetReferenceInfo ( Compilation compilation , ISymbol symbolToFind )
559562 {
0 commit comments