88using Microsoft . CodeAnalysis . Host ;
99using Microsoft . CodeAnalysis . Host . Mef ;
1010using Microsoft . CodeAnalysis . LanguageServer . Handler . DebugConfiguration ;
11+ using Microsoft . CodeAnalysis . LanguageServer . Services ;
1112using Microsoft . CodeAnalysis . ProjectSystem ;
1213using Microsoft . CodeAnalysis . Workspaces . ProjectSystem ;
1314using Microsoft . Extensions . Logging ;
1415using Microsoft . VisualStudio . Composition ;
16+ using Roslyn . Utilities ;
1517
1618namespace Microsoft . CodeAnalysis . LanguageServer . HostWorkspace ;
1719
1820[ Export ( typeof ( LanguageServerWorkspaceFactory ) ) , Shared ]
1921internal sealed class LanguageServerWorkspaceFactory
2022{
2123 private readonly ILogger _logger ;
24+ private readonly ImmutableArray < string > _solutionLevelAnalyzerPaths ;
2225
2326 [ ImportingConstructor ]
2427 [ Obsolete ( MefConstruction . ImportingConstructorMessage , error : true ) ]
@@ -28,12 +31,24 @@ public LanguageServerWorkspaceFactory(
2831 [ ImportMany ] IEnumerable < Lazy < IDynamicFileInfoProvider , FileExtensionsMetadata > > dynamicFileInfoProviders ,
2932 ProjectTargetFrameworkManager projectTargetFrameworkManager ,
3033 ServerConfigurationFactory serverConfigurationFactory ,
34+ ExtensionAssemblyManager extensionManager ,
3135 ILoggerFactory loggerFactory )
3236 {
3337 _logger = loggerFactory . CreateLogger ( nameof ( LanguageServerWorkspaceFactory ) ) ;
3438
39+ // Before we can create the workspace, let's figure out the solution-level analyzers; we'll pull in analyzers from our own binaries
40+ // as well as anything coming from extensions.
41+ _solutionLevelAnalyzerPaths = new DirectoryInfo ( AppContext . BaseDirectory ) . GetFiles ( "*.dll" )
42+ . Where ( f => f . Name . StartsWith ( "Microsoft.CodeAnalysis." , StringComparison . Ordinal ) && ! f . Name . Contains ( "LanguageServer" , StringComparison . Ordinal ) )
43+ . Select ( f => f . FullName )
44+ . Concat ( extensionManager . ExtensionAssemblyPaths )
45+ . ToImmutableArray ( ) ;
46+
47+ // Create the workspace and set analyzer references for it
3548 var workspace = new LanguageServerWorkspace ( hostServicesProvider . HostServices ) ;
49+ workspace . SetCurrentSolution ( s => s . WithAnalyzerReferences ( CreateSolutionLevelAnalyzerReferencesForWorkspace ( workspace ) ) , WorkspaceChangeKind . SolutionChanged ) ;
3650 Workspace = workspace ;
51+
3752 ProjectSystemProjectFactory = new ProjectSystemProjectFactory (
3853 Workspace , fileChangeWatcher , static ( _ , _ ) => Task . CompletedTask , _ => { } ,
3954 CancellationToken . None ) ; // TODO: do we need to introduce a shutdown cancellation token for this?
@@ -54,17 +69,17 @@ public LanguageServerWorkspaceFactory(
5469 public ProjectSystemHostInfo ProjectSystemHostInfo { get ; }
5570 public ProjectTargetFrameworkManager TargetFrameworkManager { get ; }
5671
57- public async Task InitializeSolutionLevelAnalyzersAsync ( ImmutableArray < string > analyzerPaths )
72+ public ImmutableArray < AnalyzerFileReference > CreateSolutionLevelAnalyzerReferencesForWorkspace ( Workspace workspace )
5873 {
59- var references = new List < AnalyzerFileReference > ( ) ;
60- var loaderProvider = Workspace . Services . GetRequiredService < IAnalyzerAssemblyLoaderProvider > ( ) ;
74+ var references = ImmutableArray . CreateBuilder < AnalyzerFileReference > ( ) ;
75+ var loaderProvider = workspace . Services . GetRequiredService < IAnalyzerAssemblyLoaderProvider > ( ) ;
6176
6277 // Load all analyzers into a fresh shadow copied load context. In the future, if we want to support reloading
6378 // of solution-level analyzer references, we should just need to listen for changes to those analyzer paths and
6479 // then call back into this method to update the solution accordingly.
6580 var analyzerLoader = loaderProvider . CreateNewShadowCopyLoader ( ) ;
6681
67- foreach ( var analyzerPath in analyzerPaths )
82+ foreach ( var analyzerPath in _solutionLevelAnalyzerPaths )
6883 {
6984 if ( File . Exists ( analyzerPath ) )
7085 {
@@ -77,9 +92,6 @@ public async Task InitializeSolutionLevelAnalyzersAsync(ImmutableArray<string> a
7792 }
7893 }
7994
80- await ProjectSystemProjectFactory . ApplyChangeToWorkspaceAsync ( w =>
81- {
82- w . SetCurrentSolution ( s => s . WithAnalyzerReferences ( references ) , WorkspaceChangeKind . SolutionChanged ) ;
83- } ) ;
95+ return references . ToImmutableAndClear ( ) ;
8496 }
8597}
0 commit comments