Skip to content

Commit f06d87c

Browse files
committed
Nullable enable analyzer driver
1 parent 914a80a commit f06d87c

20 files changed

Lines changed: 1191 additions & 969 deletions

src/Compilers/Core/AnalyzerDriver/DeclarationInfo.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
#nullable enable
6+
57
using System.Collections.Immutable;
68
using System.Diagnostics;
79

@@ -12,11 +14,7 @@ namespace Microsoft.CodeAnalysis
1214
/// </summary>
1315
internal readonly struct DeclarationInfo
1416
{
15-
private readonly SyntaxNode _declaredNode;
16-
private readonly ImmutableArray<SyntaxNode> _executableCodeBlocks;
17-
private readonly ISymbol _declaredSymbol;
18-
19-
internal DeclarationInfo(SyntaxNode declaredNode, ImmutableArray<SyntaxNode> executableCodeBlocks, ISymbol declaredSymbol)
17+
internal DeclarationInfo(SyntaxNode declaredNode, ImmutableArray<SyntaxNode> executableCodeBlocks, ISymbol? declaredSymbol)
2018
{
2119
Debug.Assert(declaredNode != null);
2220
Debug.Assert(!executableCodeBlocks.IsDefault);
@@ -25,24 +23,24 @@ internal DeclarationInfo(SyntaxNode declaredNode, ImmutableArray<SyntaxNode> exe
2523
// Declared node is the identifier, which doesn't contain the initializer. Can we tweak the assert somehow to handle this case?
2624
// Debug.Assert(executableCodeBlocks.All(n => n.Ancestors().Contains(declaredNode)));
2725

28-
_declaredNode = declaredNode;
29-
_executableCodeBlocks = executableCodeBlocks;
30-
_declaredSymbol = declaredSymbol;
26+
DeclaredNode = declaredNode;
27+
ExecutableCodeBlocks = executableCodeBlocks;
28+
DeclaredSymbol = declaredSymbol;
3129
}
3230

3331
/// <summary>
3432
/// Topmost syntax node for this declaration.
3533
/// </summary>
36-
public SyntaxNode DeclaredNode => _declaredNode;
34+
public SyntaxNode DeclaredNode { get; }
3735

3836
/// <summary>
3937
/// Syntax nodes for executable code blocks (method body, initializers, etc.) associated with this declaration.
4038
/// </summary>
41-
public ImmutableArray<SyntaxNode> ExecutableCodeBlocks => _executableCodeBlocks;
39+
public ImmutableArray<SyntaxNode> ExecutableCodeBlocks { get; }
4240

4341
/// <summary>
4442
/// Symbol declared by this declaration.
4543
/// </summary>
46-
public ISymbol DeclaredSymbol => _declaredSymbol;
44+
public ISymbol? DeclaredSymbol { get; }
4745
}
4846
}

src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.PerAnalyzerState.cs

Lines changed: 72 additions & 39 deletions
Large diffs are not rendered by default.

src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs

Lines changed: 48 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
#nullable enable
6+
57
using System;
68
using System.Collections.Generic;
79
using System.Collections.Immutable;
810
using System.Diagnostics;
11+
using System.Diagnostics.CodeAnalysis;
912
using System.Linq;
10-
using System.Runtime.CompilerServices;
1113
using System.Threading;
1214
using System.Threading.Tasks;
1315
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
@@ -49,7 +51,15 @@ internal partial class AnalysisState
4951
/// <summary>
5052
/// Action counts per-analyzer.
5153
/// </summary>
52-
private ImmutableDictionary<DiagnosticAnalyzer, AnalyzerActionCounts> _lazyAnalyzerActionCountsMap;
54+
private ImmutableDictionary<DiagnosticAnalyzer, AnalyzerActionCounts>? _lazyAnalyzerActionCountsMap;
55+
private ImmutableDictionary<DiagnosticAnalyzer, AnalyzerActionCounts> AnalyzerActionCountsMap
56+
{
57+
get
58+
{
59+
Debug.Assert(_lazyAnalyzerActionCountsMap != null);
60+
return _lazyAnalyzerActionCountsMap;
61+
}
62+
}
5363

5464
private readonly HashSet<ISymbol> _partialSymbolsWithGeneratedSourceEvents;
5565
private readonly CompilationData _compilationData;
@@ -66,7 +76,6 @@ public AnalysisState(ImmutableArray<DiagnosticAnalyzer> analyzers, CompilationDa
6676
_compilationOptions = compilationOptions;
6777
_pendingSourceEvents = new Dictionary<SyntaxTree, HashSet<CompilationEvent>>();
6878
_pendingNonSourceEvents = new HashSet<CompilationEvent>();
69-
_lazyAnalyzerActionCountsMap = null;
7079
_partialSymbolsWithGeneratedSourceEvents = new HashSet<ISymbol>();
7180
_compilationEventsPool = new ObjectPool<HashSet<CompilationEvent>>(() => new HashSet<CompilationEvent>());
7281
_pooledEventsWithAnyActionsSet = new HashSet<CompilationEvent>();
@@ -118,19 +127,17 @@ public async Task OnCompilationEventsGeneratedAsync(ImmutableArray<CompilationEv
118127

119128
private void OnCompilationEventsGenerated_NoLock(ImmutableArray<CompilationEvent> compilationEvents)
120129
{
121-
Debug.Assert(_lazyAnalyzerActionCountsMap != null);
122-
123130
// Add the events to our global pending events map.
124131
AddToEventsMap_NoLock(compilationEvents);
125132

126133
// Mark the events for analysis for each analyzer.
127-
ArrayBuilder<ISymbol> newPartialSymbols = null;
134+
ArrayBuilder<ISymbol>? newPartialSymbols = null;
128135
Debug.Assert(_pooledEventsWithAnyActionsSet.Count == 0);
129136
foreach (var kvp in _analyzerStateMap)
130137
{
131138
var analyzer = kvp.Key;
132139
var analyzerState = _analyzerStates[kvp.Value];
133-
var actionCounts = _lazyAnalyzerActionCountsMap[analyzer];
140+
var actionCounts = AnalyzerActionCountsMap[analyzer];
134141

135142
foreach (var compilationEvent in compilationEvents)
136143
{
@@ -148,7 +155,7 @@ private void OnCompilationEventsGenerated_NoLock(ImmutableArray<CompilationEvent
148155
}
149156
else
150157
{
151-
newPartialSymbols = newPartialSymbols ?? ArrayBuilder<ISymbol>.GetInstance();
158+
newPartialSymbols ??= ArrayBuilder<ISymbol>.GetInstance();
152159
newPartialSymbols.Add(symbolDeclaredEvent.Symbol);
153160
}
154161
}
@@ -184,8 +191,7 @@ private void AddToEventsMap_NoLock(ImmutableArray<CompilationEvent> compilationE
184191

185192
private void UpdateEventsMap_NoLock(CompilationEvent compilationEvent, bool add)
186193
{
187-
var symbolEvent = compilationEvent as SymbolDeclaredCompilationEvent;
188-
if (symbolEvent != null)
194+
if (compilationEvent is SymbolDeclaredCompilationEvent symbolEvent)
189195
{
190196
// Add/remove symbol events.
191197
// Any diagnostics request for a tree should trigger symbol and syntax node analysis for symbols with at least one declaring reference in the tree.
@@ -207,8 +213,7 @@ private void UpdateEventsMap_NoLock(CompilationEvent compilationEvent, bool add)
207213
else
208214
{
209215
// Add/remove compilation unit completed events.
210-
var compilationUnitCompletedEvent = compilationEvent as CompilationUnitCompletedEvent;
211-
if (compilationUnitCompletedEvent != null)
216+
if (compilationEvent is CompilationUnitCompletedEvent compilationUnitCompletedEvent)
212217
{
213218
var tree = compilationUnitCompletedEvent.SemanticModel.SyntaxTree;
214219
if (add)
@@ -241,8 +246,7 @@ private void UpdateEventsMap_NoLock(CompilationEvent compilationEvent, bool add)
241246

242247
private void AddPendingSourceEvent_NoLock(SyntaxTree tree, CompilationEvent compilationEvent)
243248
{
244-
HashSet<CompilationEvent> currentEvents;
245-
if (!_pendingSourceEvents.TryGetValue(tree, out currentEvents))
249+
if (!_pendingSourceEvents.TryGetValue(tree, out var currentEvents))
246250
{
247251
currentEvents = new HashSet<CompilationEvent>();
248252
_pendingSourceEvents[tree] = currentEvents;
@@ -254,8 +258,7 @@ private void AddPendingSourceEvent_NoLock(SyntaxTree tree, CompilationEvent comp
254258

255259
private void RemovePendingSourceEvent_NoLock(SyntaxTree tree, CompilationEvent compilationEvent)
256260
{
257-
HashSet<CompilationEvent> currentEvents;
258-
if (_pendingSourceEvents.TryGetValue(tree, out currentEvents))
261+
if (_pendingSourceEvents.TryGetValue(tree, out var currentEvents))
259262
{
260263
if (currentEvents.Remove(compilationEvent) && currentEvents.Count == 0)
261264
{
@@ -283,35 +286,21 @@ private async Task EnsureAnalyzerActionCountsInitializedAsync(AnalyzerDriver dri
283286
internal async Task<AnalyzerActionCounts> GetOrComputeAnalyzerActionCountsAsync(DiagnosticAnalyzer analyzer, AnalyzerDriver driver, CancellationToken cancellationToken)
284287
{
285288
await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);
286-
return _lazyAnalyzerActionCountsMap[analyzer];
289+
return AnalyzerActionCountsMap[analyzer];
287290
}
288291

289292
internal AnalyzerActionCounts GetAnalyzerActionCounts(DiagnosticAnalyzer analyzer)
290-
{
291-
Debug.Assert(_lazyAnalyzerActionCountsMap != null);
292-
return _lazyAnalyzerActionCountsMap[analyzer];
293-
}
293+
=> AnalyzerActionCountsMap[analyzer];
294294

295295
private static bool HasActionsForEvent(CompilationEvent compilationEvent, AnalyzerActionCounts actionCounts)
296296
{
297-
if (compilationEvent is CompilationStartedEvent)
298-
{
299-
return actionCounts.CompilationActionsCount > 0 ||
300-
actionCounts.SyntaxTreeActionsCount > 0 ||
301-
actionCounts.AdditionalFileActionsCount > 0;
302-
}
303-
else if (compilationEvent is CompilationCompletedEvent)
297+
return compilationEvent switch
304298
{
305-
return actionCounts.CompilationEndActionsCount > 0;
306-
}
307-
else if (compilationEvent is SymbolDeclaredCompilationEvent)
308-
{
309-
return actionCounts.SymbolActionsCount > 0 || actionCounts.HasAnyExecutableCodeActions;
310-
}
311-
else
312-
{
313-
return actionCounts.SemanticModelActionsCount > 0;
314-
}
299+
CompilationStartedEvent => actionCounts.CompilationActionsCount > 0 || actionCounts.SyntaxTreeActionsCount > 0 || actionCounts.AdditionalFileActionsCount > 0,
300+
CompilationCompletedEvent => actionCounts.CompilationEndActionsCount > 0,
301+
SymbolDeclaredCompilationEvent => actionCounts.SymbolActionsCount > 0 || actionCounts.HasAnyExecutableCodeActions,
302+
_ => actionCounts.SemanticModelActionsCount > 0
303+
};
315304
}
316305

317306
private async Task OnSymbolDeclaredEventProcessedAsync(
@@ -336,8 +325,7 @@ private async Task OnSymbolDeclaredEventProcessedAsync(
336325
public async Task OnCompilationEventProcessedAsync(CompilationEvent compilationEvent, ImmutableArray<DiagnosticAnalyzer> analyzers, Func<ISymbol, DiagnosticAnalyzer, Task> onSymbolAndMembersProcessedAsync)
337326
{
338327
// Analyze if the symbol and all its declaring syntax references are analyzed.
339-
var symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent;
340-
if (symbolDeclaredEvent != null)
328+
if (compilationEvent is SymbolDeclaredCompilationEvent symbolDeclaredEvent)
341329
{
342330
await OnSymbolDeclaredEventProcessedAsync(symbolDeclaredEvent, analyzers, onSymbolAndMembersProcessedAsync).ConfigureAwait(false);
343331
}
@@ -387,12 +375,11 @@ private HashSet<CompilationEvent> GetPendingEvents_NoLock(ImmutableArray<Diagnos
387375
/// </summary>
388376
private ImmutableArray<CompilationEvent> GetPendingEvents_NoLock(ImmutableArray<DiagnosticAnalyzer> analyzers, SyntaxTree tree)
389377
{
390-
HashSet<CompilationEvent> compilationEventsForTree;
391-
if (_pendingSourceEvents.TryGetValue(tree, out compilationEventsForTree))
378+
if (_pendingSourceEvents.TryGetValue(tree, out var compilationEventsForTree))
392379
{
393380
if (compilationEventsForTree?.Count > 0)
394381
{
395-
HashSet<CompilationEvent> pendingEvents = null;
382+
HashSet<CompilationEvent>? pendingEvents = null;
396383
try
397384
{
398385
pendingEvents = GetPendingEvents_NoLock(analyzers);
@@ -433,7 +420,7 @@ public ImmutableArray<CompilationEvent> GetPendingEvents(
433420

434421
private ImmutableArray<CompilationEvent> GetPendingEvents_NoLock(ImmutableArray<DiagnosticAnalyzer> analyzers, bool includeSourceEvents, bool includeNonSourceEvents)
435422
{
436-
HashSet<CompilationEvent> pendingEvents = null, uniqueEvents = null;
423+
HashSet<CompilationEvent>? pendingEvents = null, uniqueEvents = null;
437424
try
438425
{
439426
pendingEvents = GetPendingEvents_NoLock(analyzers);
@@ -473,7 +460,7 @@ private ImmutableArray<CompilationEvent> GetPendingEvents_NoLock(ImmutableArray<
473460
}
474461
}
475462

476-
private void Free(HashSet<CompilationEvent> events)
463+
private void Free(HashSet<CompilationEvent>? events)
477464
{
478465
if (events != null)
479466
{
@@ -533,12 +520,9 @@ public bool HasPendingSymbolAnalysis(AnalysisScope analysisScope, CancellationTo
533520

534521
private ImmutableArray<SymbolDeclaredCompilationEvent> GetPendingSymbolDeclaredEvents(SyntaxTree tree, CancellationToken cancellationToken)
535522
{
536-
Debug.Assert(tree != null);
537-
538523
using (_gate.DisposableWait(cancellationToken))
539524
{
540-
HashSet<CompilationEvent> compilationEvents;
541-
if (!_pendingSourceEvents.TryGetValue(tree, out compilationEvents))
525+
if (!_pendingSourceEvents.TryGetValue(tree, out var compilationEvents))
542526
{
543527
return ImmutableArray<SymbolDeclaredCompilationEvent>.Empty;
544528
}
@@ -554,7 +538,10 @@ private ImmutableArray<SymbolDeclaredCompilationEvent> GetPendingSymbolDeclaredE
554538
/// Returns false if the event has already been processed for the analyzer OR is currently being processed by another task.
555539
/// If true, then it returns a non-null <paramref name="state"/> representing partial analysis state for the given event for the given analyzer.
556540
/// </returns>
557-
public bool TryStartProcessingEvent(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer, out AnalyzerStateData state)
541+
public bool TryStartProcessingEvent(
542+
CompilationEvent compilationEvent,
543+
DiagnosticAnalyzer analyzer,
544+
[NotNullWhen(returnValue: true)] out AnalyzerStateData? state)
558545
{
559546
return GetAnalyzerState(analyzer).TryStartProcessingEvent(compilationEvent, out state);
560547
}
@@ -602,7 +589,7 @@ public bool IsEventComplete(CompilationEvent compilationEvent, DiagnosticAnalyze
602589
/// Returns false if the symbol has already been processed for the analyzer OR is currently being processed by another task.
603590
/// If true, then it returns a non-null <paramref name="state"/> representing partial analysis state for the given symbol for the given analyzer.
604591
/// </returns>
605-
public bool TryStartAnalyzingSymbol(ISymbol symbol, DiagnosticAnalyzer analyzer, out AnalyzerStateData state)
592+
public bool TryStartAnalyzingSymbol(ISymbol symbol, DiagnosticAnalyzer analyzer, [NotNullWhen(returnValue: true)] out AnalyzerStateData? state)
606593
{
607594
return GetAnalyzerState(analyzer).TryStartAnalyzingSymbol(symbol, out state);
608595
}
@@ -614,7 +601,7 @@ public bool TryStartAnalyzingSymbol(ISymbol symbol, DiagnosticAnalyzer analyzer,
614601
/// Returns false if the symbol end actions have already been executed for the analyzer OR are currently being executed by another task.
615602
/// If true, then it returns a non-null <paramref name="state"/> representing partial analysis state for the given symbol end actions for the given analyzer.
616603
/// </returns>
617-
public bool TryStartSymbolEndAnalysis(ISymbol symbol, DiagnosticAnalyzer analyzer, out AnalyzerStateData state)
604+
public bool TryStartSymbolEndAnalysis(ISymbol symbol, DiagnosticAnalyzer analyzer, [NotNullWhen(returnValue: true)] out AnalyzerStateData? state)
618605
{
619606
return GetAnalyzerState(analyzer).TryStartSymbolEndAnalysis(symbol, out state);
620607
}
@@ -678,7 +665,11 @@ public bool IsSymbolEndAnalysisComplete(ISymbol symbol, DiagnosticAnalyzer analy
678665
/// Returns false if the declaration has already been processed for the analyzer OR is currently being processed by another task.
679666
/// If true, then it returns a non-null <paramref name="state"/> representing partial analysis state for the given declaration for the given analyzer.
680667
/// </returns>
681-
public bool TryStartAnalyzingDeclaration(ISymbol symbol, int declarationIndex, DiagnosticAnalyzer analyzer, out DeclarationAnalyzerStateData state)
668+
public bool TryStartAnalyzingDeclaration(
669+
ISymbol symbol,
670+
int declarationIndex,
671+
DiagnosticAnalyzer analyzer,
672+
[NotNullWhen(returnValue: true)] out DeclarationAnalyzerStateData? state)
682673
{
683674
return GetAnalyzerState(analyzer).TryStartAnalyzingDeclaration(symbol, declarationIndex, out state);
684675
}
@@ -750,7 +741,10 @@ public void MarkDeclarationsComplete(ISymbol symbol, IEnumerable<DiagnosticAnaly
750741
/// Returns false if the file has already been processed for the analyzer OR is currently being processed by another task.
751742
/// If true, then it returns a non-null <paramref name="state"/> representing partial syntax analysis state for the given tree for the given analyzer.
752743
/// </returns>
753-
public bool TryStartSyntaxAnalysis(SourceOrAdditionalFile file, DiagnosticAnalyzer analyzer, out AnalyzerStateData state)
744+
public bool TryStartSyntaxAnalysis(
745+
SourceOrAdditionalFile file,
746+
DiagnosticAnalyzer analyzer,
747+
[NotNullWhen(returnValue: true)] out AnalyzerStateData? state)
754748
{
755749
return GetAnalyzerState(analyzer).TryStartSyntaxAnalysis(file, out state);
756750
}

src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.CompilationData.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
#nullable enable
6+
57
using System;
68
using System.Collections.Generic;
7-
using System.Collections.Immutable;
8-
using System.Runtime.CompilerServices;
99
using System.Threading;
10-
using Microsoft.CodeAnalysis.PooledObjects;
11-
using Roslyn.Utilities;
1210

1311
namespace Microsoft.CodeAnalysis.Diagnostics
1412
{
@@ -35,7 +33,7 @@ public CompilationData(Compilation comp)
3533

3634
public SemanticModel GetOrCreateCachedSemanticModel(SyntaxTree tree, Compilation compilation, CancellationToken cancellationToken)
3735
{
38-
SemanticModel model;
36+
SemanticModel? model;
3937
lock (_semanticModelsMap)
4038
{
4139
if (_semanticModelsMap.TryGetValue(tree, out model) && model.Compilation == compilation)
@@ -74,7 +72,7 @@ internal DeclarationAnalysisData GetOrComputeDeclarationAnalysisData(
7472

7573
lock (_declarationAnalysisDataMap)
7674
{
77-
if (_declarationAnalysisDataMap.TryGetValue(declaration, out DeclarationAnalysisData cachedData))
75+
if (_declarationAnalysisDataMap.TryGetValue(declaration, out var cachedData))
7876
{
7977
return cachedData;
8078
}
@@ -84,7 +82,7 @@ internal DeclarationAnalysisData GetOrComputeDeclarationAnalysisData(
8482

8583
lock (_declarationAnalysisDataMap)
8684
{
87-
if (!_declarationAnalysisDataMap.TryGetValue(declaration, out DeclarationAnalysisData existingData))
85+
if (!_declarationAnalysisDataMap.TryGetValue(declaration, out var existingData))
8886
{
8987
_declarationAnalysisDataMap.Add(declaration, data);
9088
}

src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.DeclarationAnalysisData.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
#nullable enable
6+
57
using System;
68
using System.Collections.Immutable;
79

0 commit comments

Comments
 (0)