@@ -44,7 +44,6 @@ public static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic
4444
4545 var document = fixAllContext . Document ;
4646 var project = fixAllContext . Project ;
47- var analyzers = GetDiagnosticAnalyzersForContext ( fixAllContext ) ;
4847
4948 switch ( fixAllContext . Scope )
5049 {
@@ -59,7 +58,7 @@ public static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic
5958
6059 case FixAllScope . Project :
6160 projectsToFix = ImmutableArray . Create ( project ) ;
62- allDiagnostics = await GetAllDiagnosticsAsync ( fixAllContext , project , analyzers ) . ConfigureAwait ( false ) ;
61+ allDiagnostics = await GetAllDiagnosticsAsync ( fixAllContext , project ) . ConfigureAwait ( false ) ;
6362 break ;
6463
6564 case FixAllScope . Solution :
@@ -76,7 +75,7 @@ public static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic
7675 tasks [ i ] = Task . Run (
7776 async ( ) =>
7877 {
79- var projectDiagnostics = await GetAllDiagnosticsAsync ( fixAllContext , projectToFix , analyzers ) . ConfigureAwait ( false ) ;
78+ var projectDiagnostics = await GetAllDiagnosticsAsync ( fixAllContext , projectToFix ) . ConfigureAwait ( false ) ;
8079 diagnostics . TryAdd ( projectToFix . Id , projectDiagnostics ) ;
8180 } , fixAllContext . CancellationToken ) ;
8281 }
@@ -171,44 +170,65 @@ private static ImmutableArray<DiagnosticAnalyzer> GetDiagnosticAnalyzersForConte
171170 . ToImmutableArray ( ) ;
172171 }
173172
174- private static async Task < ImmutableArray < Diagnostic > > GetAllDiagnosticsAsync ( FixAllContext fixAllContext , Project project , ImmutableArray < DiagnosticAnalyzer > analyzers )
173+ /// <summary>
174+ /// Gets all <see cref="Diagnostic"/> instances within a specific <see cref="Project"/> which are relevant to a
175+ /// <see cref="FixAllContext"/>.
176+ /// </summary>
177+ /// <param name="fixAllContext">The context for the Fix All operation.</param>
178+ /// <param name="project">The project.</param>
179+ /// <returns>A <see cref="Task{TResult}"/> representing the asynchronous operation. When the task completes
180+ /// successfully, the <see cref="Task{TResult}.Result"/> will contain the requested diagnostics.</returns>
181+ private static async Task < ImmutableArray < Diagnostic > > GetAllDiagnosticsAsync ( FixAllContext fixAllContext , Project project )
175182 {
183+ if ( GetAnalyzerSyntaxDiagnosticsAsync == null || GetAnalyzerSemanticDiagnosticsAsync == null )
184+ {
185+ return await fixAllContext . GetAllDiagnosticsAsync ( project ) . ConfigureAwait ( false ) ;
186+ }
187+
188+ /*
189+ * The rest of this method is workaround code for issues with Roslyn 1.1...
190+ */
191+
192+ var analyzers = GetDiagnosticAnalyzersForContext ( fixAllContext ) ;
193+
194+ // Most code fixes in this project operate on diagnostics reported by analyzers in this project. However, a
195+ // few code fixes also operate on standard warnings produced by the C# compiler. Special handling is
196+ // required for the latter case since these warnings are not considered "analyzer diagnostics".
176197 bool includeCompilerDiagnostics = fixAllContext . DiagnosticIds . Any ( x => x . StartsWith ( "CS" , StringComparison . Ordinal ) ) ;
198+
199+ // Use a single CompilationWithAnalyzers for the entire operation. This allows us to use the
200+ // GetDeclarationDiagnostics workaround for dotnet/roslyn#7446 a single time, rather than once per document.
177201 var compilation = await project . GetCompilationAsync ( fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
202+ var compilationWithAnalyzers = compilation . WithAnalyzers ( analyzers , project . AnalyzerOptions , fixAllContext . CancellationToken ) ;
203+ compilationWithAnalyzers . Compilation . GetDeclarationDiagnostics ( fixAllContext . CancellationToken ) ;
178204
205+ // Note that the following loop to obtain syntax and semantic diagnostics for each document cannot operate
206+ // on parallel due to our use of a single CompilationWithAnalyzers instance. Also note that the following
207+ // code is not sufficient for cases where analyzers register compilation end actions. However, this project
208+ // does not currently contain any such analyzers.
179209 var diagnostics = ImmutableArray < Diagnostic > . Empty ;
180- if ( analyzers . Any ( ) )
210+ foreach ( var document in project . Documents )
181211 {
182- var compilationWithAnalyzers = compilation . WithAnalyzers ( analyzers , project . AnalyzerOptions , fixAllContext . CancellationToken ) ;
183- if ( GetAnalyzerSyntaxDiagnosticsAsync != null && GetAnalyzerSemanticDiagnosticsAsync != null )
184- {
185- // This whole block is workaround code for issues with Roslyn 1.1...
186- compilationWithAnalyzers . Compilation . GetDeclarationDiagnostics ( fixAllContext . CancellationToken ) ;
187-
188- foreach ( var document in project . Documents )
189- {
190- var syntaxTree = await document . GetSyntaxTreeAsync ( fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
191- var syntaxDiagnostics = await GetAnalyzerSyntaxDiagnosticsAsync ( compilationWithAnalyzers , syntaxTree , fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
192- diagnostics = diagnostics . AddRange ( syntaxDiagnostics ) ;
212+ var syntaxTree = await document . GetSyntaxTreeAsync ( fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
213+ var syntaxDiagnostics = await GetAnalyzerSyntaxDiagnosticsAsync ( compilationWithAnalyzers , syntaxTree , fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
214+ diagnostics = diagnostics . AddRange ( syntaxDiagnostics ) ;
193215
194- var semanticModel = await document . GetSemanticModelAsync ( fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
195- var semanticDiagnostics = await GetAnalyzerSemanticDiagnosticsAsync ( compilationWithAnalyzers , semanticModel , default ( TextSpan ? ) , fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
196- diagnostics = diagnostics . AddRange ( semanticDiagnostics ) ;
197- }
198- }
199- else
200- {
201- diagnostics = await compilationWithAnalyzers . GetAnalyzerDiagnosticsAsync ( ) . ConfigureAwait ( false ) ;
202- }
216+ var semanticModel = await document . GetSemanticModelAsync ( fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
217+ var semanticDiagnostics = await GetAnalyzerSemanticDiagnosticsAsync ( compilationWithAnalyzers , semanticModel , default ( TextSpan ? ) , fixAllContext . CancellationToken ) . ConfigureAwait ( false ) ;
218+ diagnostics = diagnostics . AddRange ( semanticDiagnostics ) ;
203219 }
204220
205221 if ( includeCompilerDiagnostics )
206222 {
223+ // This is the special handling for cases where code fixes operate on warnings produced by the C#
224+ // compiler, as opposed to being created by specific analyzers.
207225 var compilerDiagnostics = compilation . GetDiagnostics ( fixAllContext . CancellationToken ) ;
208226 diagnostics = diagnostics . AddRange ( compilerDiagnostics ) ;
209227 }
210228
211- diagnostics = diagnostics . Where ( x => fixAllContext . DiagnosticIds . Contains ( x . Id ) ) . ToImmutableArray ( ) ;
229+ // Make sure to filter the results to the set requested for the Fix All operation, since analyzers can
230+ // report diagnostics with different IDs.
231+ diagnostics = diagnostics . RemoveAll ( x => ! fixAllContext . DiagnosticIds . Contains ( x . Id ) ) ;
212232 return diagnostics ;
213233 }
214234
0 commit comments