1010using Microsoft . CodeAnalysis . CodeFixes ;
1111using Microsoft . CodeAnalysis . CodeRefactorings ;
1212using Microsoft . CodeAnalysis . Completion ;
13+ using Microsoft . CodeAnalysis . CSharp . DecompiledSource ;
1314using Microsoft . CodeAnalysis . CSharp . Syntax ;
1415using Microsoft . CodeAnalysis . Diagnostics ;
1516using Microsoft . CodeAnalysis . FindSymbols ;
1617using Microsoft . CodeAnalysis . Host . Mef ;
18+ using Microsoft . CodeAnalysis . MetadataAsSource ;
1719using Microsoft . CodeAnalysis . MSBuild ;
1820using Microsoft . CodeAnalysis . Options ;
1921using Microsoft . CodeAnalysis . PooledObjects ;
@@ -60,6 +62,7 @@ public partial class RoslynAnalysis(ILogger<RoslynAnalysis> logger, BuildService
6062 private static ICodeFixService ? _codeFixService ;
6163 private static ICodeRefactoringService ? _codeRefactoringService ;
6264 private static IDocumentMappingService ? _documentMappingService ;
65+ private static IMetadataAsSourceFileService _metadataAsSourceFileService = null ! ;
6366 private static SignatureHelpService _signatureHelpService = null ! ;
6467 private static HashSet < CodeRefactoringProvider > _codeRefactoringProviders = [ ] ;
6568 private static HashSet < CodeFixProvider > _codeFixProviders = [ ] ;
@@ -97,6 +100,7 @@ public async Task LoadSolutionInWorkspace(SharpIdeSolutionModel solutionModel, C
97100 var configuration = new ContainerConfiguration ( )
98101 . WithAssemblies ( MefHostServices . DefaultAssemblies )
99102 . WithAssembly ( typeof ( RemoteSnapshotManager ) . Assembly )
103+ . WithPart < CSharpDecompilationService2 > ( )
100104 . WithPart < PythiaStub > ( ) ;
101105
102106 // TODO: dispose container at some point?
@@ -112,7 +116,8 @@ public async Task LoadSolutionInWorkspace(SharpIdeSolutionModel solutionModel, C
112116 _codeFixService = container . GetExports < ICodeFixService > ( ) . FirstOrDefault ( ) ;
113117 _codeRefactoringService = container . GetExports < ICodeRefactoringService > ( ) . FirstOrDefault ( ) ;
114118 _signatureHelpService = container . GetExports < SignatureHelpService > ( ) . FirstOrDefault ( ) ! ;
115-
119+ // TODO: Write an implementation of ISourceLinkService, as MS's implementation does not appear to be open source
120+ _metadataAsSourceFileService = container . GetExports < IMetadataAsSourceFileService > ( ) . FirstOrDefault ( ) ! ;
116121 _semanticTokensLegendService = ( RemoteSemanticTokensLegendService ) container . GetExports < ISemanticTokensLegendService > ( ) . FirstOrDefault ( ) ! ;
117122 _semanticTokensLegendService ! . OnLspInitialized ( new RemoteClientLSPInitializationOptions
118123 {
@@ -400,6 +405,7 @@ public async Task<ImmutableArray<SharpIdeDiagnostic>> GetProjectDiagnosticsForFi
400405 public async Task < ImmutableArray < SharpIdeDiagnostic > > GetDocumentDiagnostics ( SharpIdeFile fileModel , CancellationToken cancellationToken = default )
401406 {
402407 if ( fileModel . IsRoslynWorkspaceFile is false ) return [ ] ;
408+ if ( fileModel . IsMetadataAsSourceFile ) return [ ] ; // Due to the current nature of IMetadataAsSourceFileService, which only decompiles a single document (not the whole project), if this was enabled, we would get error diagnostics for missing references to other "files" in the same dll
403409 using var _ = SharpIdeOtel . Source . StartActivity ( $ "{ nameof ( RoslynAnalysis ) } .{ nameof ( GetDocumentDiagnostics ) } ") ;
404410 await _solutionLoadedTcs . Task ;
405411
@@ -424,6 +430,7 @@ public async Task<ImmutableArray<SharpIdeDiagnostic>> GetDocumentDiagnostics(Sha
424430 public async Task < ImmutableArray < SharpIdeDiagnostic > > GetDocumentAnalyzerDiagnostics ( SharpIdeFile fileModel , CancellationToken cancellationToken = default )
425431 {
426432 if ( fileModel . IsRoslynWorkspaceFile is false ) return [ ] ;
433+ if ( fileModel . IsMetadataAsSourceFile ) return [ ] ; // Decompiled/SourceLink files should not/will not have analyzers
427434 using var _ = SharpIdeOtel . Source . StartActivity ( $ "{ nameof ( RoslynAnalysis ) } .{ nameof ( GetDocumentAnalyzerDiagnostics ) } ") ;
428435 await _solutionLoadedTcs . Task ;
429436
@@ -599,6 +606,7 @@ public async Task<ImmutableArray<SharpIdeClassifiedSpan>> GetDocumentSyntaxHighl
599606 var root = await syntaxTree ! . GetRootAsync ( cancellationToken ) ;
600607
601608 var classifiedSpans = await Classifier . GetClassifiedSpansAsync ( document , root . FullSpan , cancellationToken ) ;
609+ //var classifiedSpans = await ClassifierHelper.GetClassifiedSpansAsync(document, root.FullSpan, ClassificationOptions.Default, true, cancellationToken);
602610 var result = classifiedSpans . Select ( s => new SharpIdeClassifiedSpan ( syntaxTree . GetMappedLineSpan ( s . TextSpan ) . Span , s ) ) . ToImmutableArray ( ) ;
603611 return result ;
604612 }
@@ -978,6 +986,23 @@ public async Task<ImmutableArray<IdeReferenceLocationResult>> GetIdeReferenceLoc
978986 return changedFilesWithText ;
979987 }
980988
989+ public async Task < string ? > GetMetadataAsSource ( SharpIdeFile currentFile , ISymbol symbol , CancellationToken cancellationToken = default )
990+ {
991+ using var _ = SharpIdeOtel . Source . StartActivity ( $ "{ nameof ( RoslynAnalysis ) } .{ nameof ( FindAllSymbolReferences ) } ") ;
992+ await _solutionLoadedTcs . Task ;
993+ if ( _metadataAsSourceFileService . IsNavigableMetadataSymbol ( symbol ) is false ) return null ;
994+
995+ var documentContainingMetadataReference = await GetDocumentForSharpIdeFile ( currentFile , cancellationToken ) ;
996+
997+ var options = MetadataAsSourceOptions . Default ; // with { NavigateToSourceLinkAndEmbeddedSources = false };
998+ var metadataAsSourceFile = await _metadataAsSourceFileService . GetGeneratedFileAsync ( _workspace ! , documentContainingMetadataReference . Project , symbol , false , options , cancellationToken ) ;
999+ Console . WriteLine ( metadataAsSourceFile . FilePath ) ;
1000+ var metadataAsSourceWorkspace = _metadataAsSourceFileService . TryGetWorkspace ( ) ;
1001+ var documentId = metadataAsSourceWorkspace ! . CurrentSolution . GetDocumentIdsWithFilePath ( metadataAsSourceFile . FilePath ) . SingleOrDefault ( ) ;
1002+ var document = metadataAsSourceWorkspace . CurrentSolution . GetDocument ( documentId ) ;
1003+ return document ? . FilePath ;
1004+ }
1005+
9811006 public async Task < ImmutableArray < ReferencedSymbol > > FindAllSymbolReferences ( ISymbol symbol , CancellationToken cancellationToken = default )
9821007 {
9831008 using var _ = SharpIdeOtel . Source . StartActivity ( $ "{ nameof ( RoslynAnalysis ) } .{ nameof ( FindAllSymbolReferences ) } ") ;
@@ -1321,6 +1346,14 @@ private static SharpIdeProjectModel GetSharpIdeProjectForSharpIdeFile(SharpIdeFi
13211346
13221347 private static Project GetProjectForSharpIdeFile ( SharpIdeFile sharpIdeFile )
13231348 {
1349+ if ( sharpIdeFile . IsMetadataAsSourceFile )
1350+ {
1351+ var metadataAsSourceWorkspace = _metadataAsSourceFileService . TryGetWorkspace ( ) ?? throw new InvalidOperationException ( "Metadata as source workspace is not available" ) ;
1352+ var documentId = metadataAsSourceWorkspace . CurrentSolution . GetDocumentIdsWithFilePath ( sharpIdeFile . Path ) . SingleOrDefault ( ) ?? throw new InvalidOperationException ( $ "Document with path '{ sharpIdeFile . Path } ' not found in metadata as source workspace") ;
1353+ var document = metadataAsSourceWorkspace . CurrentSolution . GetDocument ( documentId ) ?? throw new InvalidOperationException ( $ "Document with id '{ documentId } ' not found in metadata as source workspace") ;
1354+ var metadataAsSourceProject = document . Project ;
1355+ return metadataAsSourceProject ;
1356+ }
13241357 var sharpIdeProjectModel = GetSharpIdeProjectForSharpIdeFile ( sharpIdeFile ) ;
13251358 var project = GetProjectForSharpIdeProjectModel ( sharpIdeProjectModel ) ;
13261359 return project ;
0 commit comments