44using System . Reflection . Metadata ;
55using System . Reflection . PortableExecutable ;
66using System . Text ;
7+ using ICSharpCode . Decompiler ;
8+ using ICSharpCode . Decompiler . CSharp ;
9+ using ICSharpCode . Decompiler . CSharp . Transforms ;
710using ICSharpCode . Decompiler . Metadata ;
11+ using ICSharpCode . Decompiler . TypeSystem ;
812using Microsoft . CodeAnalysis ;
913using Microsoft . CodeAnalysis . Debugging ;
1014using Microsoft . CodeAnalysis . ErrorReporting ;
1822using Microsoft . CodeAnalysis . Text ;
1923using Roslyn . Utilities ;
2024using Document = Microsoft . CodeAnalysis . Document ;
25+ using ISymbol = Microsoft . CodeAnalysis . ISymbol ;
2126
2227namespace SharpIDE . Application . Features . Analysis . WorkspaceServices ;
2328
@@ -116,8 +121,7 @@ internal sealed class DecompileWholeAssemblyToProjectMetadataAsSourceFileProvide
116121 decompiledFiles = await GetSourceFilesFromSymbolCachePdb ( refInfo . metadataReference , refInfo . assemblyLocation , assemblyKey , cancellationToken ) ;
117122 if ( decompiledFiles is null )
118123 {
119- decompiledFiles = await DecompileAssemblyToMemoryAsync (
120- compilation , refInfo . metadataReference , refInfo . assemblyLocation , cancellationToken ) . ConfigureAwait ( false ) ;
124+ decompiledFiles = await DecompileAssemblyToMemoryAsync ( compilation , refInfo . metadataReference , refInfo . assemblyLocation , assemblyKey , cancellationToken ) ;
121125 }
122126
123127 telemetryMessage ? . SetDecompiled ( decompiledFiles is not null ) ;
@@ -180,7 +184,7 @@ internal sealed class DecompileWholeAssemblyToProjectMetadataAsSourceFileProvide
180184 if ( metadataReference is null || assemblyLocation is null ) return null ;
181185
182186 // TBD
183- var symbolCacheFolderPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , "Temp" , "SharpIdeSymbolCache" ) ;
187+ var symbolCacheFolderPath = SharpIdeDecompilationConstants . SymbolCachePath ;
184188
185189 var assemblyName = Path . GetFileNameWithoutExtension ( assemblyLocation ) ;
186190 var mvid = assemblyKey . Mvid ;
@@ -245,12 +249,14 @@ internal sealed class DecompileWholeAssemblyToProjectMetadataAsSourceFileProvide
245249 }
246250
247251 /// <summary>
248- /// Decompiles all types in the assembly to a dictionary of relative path -> source code.
252+ /// Decompiles all types in the assembly to a dictionary of relative path -> source code,
253+ /// and writes a portable PDB with embedded sources to the symbol cache.
249254 /// </summary>
250255 private static Task < Dictionary < string , string > ? > DecompileAssemblyToMemoryAsync (
251256 Compilation compilation ,
252257 MetadataReference ? metadataReference ,
253258 string ? assemblyLocation ,
259+ UniqueAssemblyKey assemblyKey ,
254260 CancellationToken cancellationToken )
255261 {
256262 return Task . Run ( Dictionary < string , string > ? ( ) =>
@@ -270,8 +276,30 @@ internal sealed class DecompileWholeAssemblyToProjectMetadataAsSourceFileProvide
270276
271277 using ( file )
272278 {
273- var decompiler = new WholeAssemblyDecompiler ( resolver ) ;
274- return decompiler . DecompileToMemory ( file , cancellationToken ) ;
279+ var settings = new DecompilerSettings ( ) ;
280+ var ts = new DecompilerTypeSystem ( file , resolver , settings ) ;
281+ var decompiler = new CSharpDecompiler ( ts , settings )
282+ {
283+ AstTransforms = {
284+ new TransformFieldAndConstructorInitializers ( ) ,
285+ new AddXmlDocumentationTransform ( ) ,
286+ new EscapeInvalidIdentifiers ( ) ,
287+ new FixNameCollisions ( ) ,
288+ new RemoveCLSCompliantAttribute ( ) ,
289+ new ReplaceMethodCallsWithOperators ( )
290+ }
291+ } ;
292+
293+ // Determine PDB cache path.
294+ var assemblyName = assemblyLocation is not null ? Path . GetFileNameWithoutExtension ( assemblyLocation ) : file . Name ;
295+ var pdbDir = Path . Combine ( SharpIdeDecompilationConstants . SymbolCachePath , assemblyName , assemblyKey . Mvid . ToString ( ) ) ;
296+ var pdbPath = Path . Combine ( pdbDir , $ "{ assemblyName } .decompiled.pdb") ;
297+ Directory . CreateDirectory ( pdbDir ) ;
298+
299+ using var pdbStream = new FileStream ( pdbPath , FileMode . Create , FileAccess . Write , FileShare . None ) ;
300+ var sourceFiles = PortablePdbWriter2 . WritePdb ( file , decompiler , settings , pdbStream , noLogo : true ) ;
301+
302+ return sourceFiles . Count > 0 ? sourceFiles : null ;
275303 }
276304 } , cancellationToken ) ;
277305 }
0 commit comments