1616using Microsoft . CodeAnalysis . Host ;
1717using Microsoft . CodeAnalysis . Host . Mef ;
1818using Microsoft . CodeAnalysis . Options ;
19+ using Microsoft . CodeAnalysis . Remote ;
1920using Microsoft . CodeAnalysis . Shared . TestHooks ;
2021using Microsoft . CodeAnalysis . SolutionCrawler ;
2122using Microsoft . CodeAnalysis . Text ;
@@ -138,20 +139,51 @@ public Task<ImmutableArray<DiagnosticData>> GetProjectDiagnosticsForIdsAsync(
138139 return _incrementalAnalyzer . GetProjectDiagnosticsForIdsAsync ( project , diagnosticIds , shouldIncludeAnalyzer , includeNonLocalDocumentDiagnostics , cancellationToken ) ;
139140 }
140141
141- public Task < ImmutableArray < DiagnosticDescriptor > > GetDiagnosticDescriptorsAsync (
142- Solution solution , AnalyzerReference analyzerReference , string language , CancellationToken cancellationToken )
142+ public async Task < ImmutableArray < DiagnosticDescriptor > > GetDiagnosticDescriptorsAsync (
143+ Solution solution , ProjectId projectId , AnalyzerReference analyzerReference , string language , CancellationToken cancellationToken )
143144 {
144- // TODO(cyrusn): Remote this to OOP.
145- var descriptors = analyzerReference
145+ // Attempt to compute this OOP.
146+ var client = await RemoteHostClient . TryGetClientAsync ( solution . Services , cancellationToken ) . ConfigureAwait ( false ) ;
147+ if ( client is not null &&
148+ analyzerReference is AnalyzerFileReference analyzerFileReference )
149+ {
150+ var descriptors = await client . TryInvokeAsync < IRemoteDiagnosticAnalyzerService , ImmutableArray < DiagnosticDescriptorData > > (
151+ solution ,
152+ ( service , solution , cancellationToken ) => service . GetDiagnosticDescriptorsAsync ( solution , projectId , analyzerFileReference . FullPath , language , cancellationToken ) ,
153+ cancellationToken ) . ConfigureAwait ( false ) ;
154+ if ( ! descriptors . HasValue )
155+ return [ ] ;
156+
157+ return descriptors . Value . SelectAsArray ( d => d . ToDiagnosticDescriptor ( ) ) ;
158+ }
159+
160+ // Otherwise, fallback to computing in proc.
161+ return analyzerReference
146162 . GetAnalyzers ( language )
147163 . SelectManyAsArray ( this . _analyzerInfoCache . GetDiagnosticDescriptors ) ;
148-
149- return Task . FromResult ( descriptors ) ;
150164 }
151165
152- public Task < ImmutableDictionary < ImmutableArray < string > , ImmutableArray < DiagnosticDescriptor > > > GetDiagnosticDescriptorsAsync (
153- Solution solution , AnalyzerReference analyzerReference , CancellationToken cancellationToken )
166+ public async Task < ImmutableDictionary < ImmutableArray < string > , ImmutableArray < DiagnosticDescriptor > > > GetLanguageKeyedDiagnosticDescriptorsAsync (
167+ Solution solution , ProjectId projectId , AnalyzerReference analyzerReference , CancellationToken cancellationToken )
154168 {
169+ var client = await RemoteHostClient . TryGetClientAsync ( solution . Services , cancellationToken ) . ConfigureAwait ( false ) ;
170+ if ( client is not null &&
171+ analyzerReference is AnalyzerFileReference analyzerFileReference )
172+ {
173+ var map = await client . TryInvokeAsync < IRemoteDiagnosticAnalyzerService , ImmutableDictionary < ImmutableArray < string > , ImmutableArray < DiagnosticDescriptorData > > > (
174+ solution ,
175+ ( service , solution , cancellationToken ) => service . GetLanguageKeyedDiagnosticDescriptorsAsync ( solution , projectId , analyzerFileReference . FullPath , cancellationToken ) ,
176+ cancellationToken ) . ConfigureAwait ( false ) ;
177+
178+ if ( ! map . HasValue )
179+ return ImmutableDictionary < ImmutableArray < string > , ImmutableArray < DiagnosticDescriptor > > . Empty ;
180+
181+ return map . Value . ToImmutableDictionary (
182+ kvp => kvp . Key ,
183+ kvp => kvp . Value . SelectAsArray ( d => d . ToDiagnosticDescriptor ( ) ) ) ;
184+ }
185+
186+ // Otherwise, fallback to computing in proc.
155187 var mapBuilder = ImmutableDictionary . CreateBuilder < ImmutableArray < string > , ImmutableArray < DiagnosticDescriptor > > ( ) ;
156188
157189 var csharpAnalyzers = analyzerReference . GetAnalyzers ( LanguageNames . CSharp ) ;
@@ -165,30 +197,80 @@ public Task<ImmutableDictionary<ImmutableArray<string>, ImmutableArray<Diagnosti
165197 mapBuilder . Add ( s_visualBasicLanguageArray , GetDiagnosticDescriptors ( visualBasicAnalyzers ) ) ;
166198 mapBuilder . Add ( s_csharpAndVisualBasicLanguageArray , GetDiagnosticDescriptors ( dotnetAnalyzers ) ) ;
167199
168- return Task . FromResult ( mapBuilder . ToImmutable ( ) ) ;
200+ return mapBuilder . ToImmutable ( ) ;
169201
170202 ImmutableArray < DiagnosticDescriptor > GetDiagnosticDescriptors ( ImmutableArray < DiagnosticAnalyzer > analyzers )
171203 => analyzers . SelectManyAsArray ( this . _analyzerInfoCache . GetDiagnosticDescriptors ) ;
172204 }
173205
174- public Task < ImmutableDictionary < string , DiagnosticDescriptor > > TryGetDiagnosticDescriptorsAsync (
206+ public async Task < ImmutableDictionary < string , DiagnosticDescriptor > > TryGetDiagnosticDescriptorsAsync (
175207 Solution solution , ImmutableArray < string > diagnosticIds , CancellationToken cancellationToken )
176208 {
209+ var client = await RemoteHostClient . TryGetClientAsync ( solution . Services , cancellationToken ) . ConfigureAwait ( false ) ;
210+ if ( client is not null )
211+ {
212+ var map = await client . TryInvokeAsync < IRemoteDiagnosticAnalyzerService , ImmutableDictionary < string , DiagnosticDescriptorData > > (
213+ solution ,
214+ ( service , solution , cancellationToken ) => service . TryGetDiagnosticDescriptorsAsync ( solution , diagnosticIds , cancellationToken ) ,
215+ cancellationToken ) . ConfigureAwait ( false ) ;
216+
217+ if ( ! map . HasValue )
218+ return ImmutableDictionary < string , DiagnosticDescriptor > . Empty ;
219+
220+ return map . Value . ToImmutableDictionary (
221+ kvp => kvp . Key ,
222+ kvp => kvp . Value . ToDiagnosticDescriptor ( ) ) ;
223+ }
224+
177225 var builder = ImmutableDictionary . CreateBuilder < string , DiagnosticDescriptor > ( ) ;
178226 foreach ( var diagnosticId in diagnosticIds )
179227 {
180228 if ( this . _analyzerInfoCache . TryGetDescriptorForDiagnosticId ( diagnosticId , out var descriptor ) )
181229 builder [ diagnosticId ] = descriptor ;
182230 }
183231
184- return Task . FromResult ( builder . ToImmutable ( ) ) ;
232+ return builder . ToImmutable ( ) ;
233+ }
234+
235+ public async Task < ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptor > > > GetDiagnosticDescriptorsPerReferenceAsync ( Solution solution , CancellationToken cancellationToken )
236+ {
237+ var client = await RemoteHostClient . TryGetClientAsync ( solution . Services , cancellationToken ) . ConfigureAwait ( false ) ;
238+ if ( client is not null )
239+ {
240+ var map = await client . TryInvokeAsync < IRemoteDiagnosticAnalyzerService , ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptorData > > > (
241+ solution ,
242+ ( service , solution , cancellationToken ) => service . GetDiagnosticDescriptorsPerReferenceAsync ( solution , cancellationToken ) ,
243+ cancellationToken ) . ConfigureAwait ( false ) ;
244+ if ( ! map . HasValue )
245+ return ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptor > > . Empty ;
246+
247+ return map . Value . ToImmutableDictionary (
248+ kvp => kvp . Key ,
249+ kvp => kvp . Value . SelectAsArray ( d => d . ToDiagnosticDescriptor ( ) ) ) ;
250+ }
251+
252+ return solution . SolutionState . Analyzers . GetDiagnosticDescriptorsPerReference ( this . _analyzerInfoCache ) ;
185253 }
186254
187- public Task < ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptor > > > GetDiagnosticDescriptorsPerReferenceAsync ( Solution solution , CancellationToken cancellationToken )
188- => Task . FromResult ( solution . SolutionState . Analyzers . GetDiagnosticDescriptorsPerReference ( this . _analyzerInfoCache ) ) ;
255+ public async Task < ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptor > > > GetDiagnosticDescriptorsPerReferenceAsync ( Project project , CancellationToken cancellationToken )
256+ {
257+ var client = await RemoteHostClient . TryGetClientAsync ( project , cancellationToken ) . ConfigureAwait ( false ) ;
258+ if ( client is not null )
259+ {
260+ var map = await client . TryInvokeAsync < IRemoteDiagnosticAnalyzerService , ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptorData > > > (
261+ project ,
262+ ( service , solution , cancellationToken ) => service . GetDiagnosticDescriptorsPerReferenceAsync ( solution , project . Id , cancellationToken ) ,
263+ cancellationToken ) . ConfigureAwait ( false ) ;
264+ if ( ! map . HasValue )
265+ return ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptor > > . Empty ;
266+
267+ return map . Value . ToImmutableDictionary (
268+ kvp => kvp . Key ,
269+ kvp => kvp . Value . SelectAsArray ( d => d . ToDiagnosticDescriptor ( ) ) ) ;
270+ }
189271
190- public Task < ImmutableDictionary < string , ImmutableArray < DiagnosticDescriptor > > > GetDiagnosticDescriptorsPerReferenceAsync ( Project project , CancellationToken cancellationToken )
191- => Task . FromResult ( project . Solution . SolutionState . Analyzers . GetDiagnosticDescriptorsPerReference ( this . _analyzerInfoCache , project ) ) ;
272+ return project . Solution . SolutionState . Analyzers . GetDiagnosticDescriptorsPerReference ( this . _analyzerInfoCache , project ) ;
273+ }
192274
193275 private sealed class DiagnosticAnalyzerComparer : IEqualityComparer < DiagnosticAnalyzer >
194276 {
0 commit comments