diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs index 1ee624698d79e8c8fe92e92196338be61326c518..9c6d206bef113d094a1f2013838c1962777ecb67 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Roslyn.Utilities; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -17,51 +18,90 @@ private class HostStates { private readonly StateManager _owner; - private ImmutableDictionary> _stateMap; + private ImmutableDictionary _stateMap; public HostStates(StateManager owner) { _owner = owner; - _stateMap = ImmutableDictionary>.Empty; + _stateMap = ImmutableDictionary.Empty; } public IEnumerable GetStateSets() { - return _stateMap.Values.SelectMany(v => v.Values); + return _stateMap.Values.SelectMany(v => v.GetStateSets()); } public IEnumerable GetOrCreateStateSets(string language) { - var map = GetAnalyzerMap(language); - return map.Values; + return GetAnalyzerMap(language).GetStateSets(); } public StateSet GetOrCreateStateSet(string language, DiagnosticAnalyzer analyzer) { - var map = GetAnalyzerMap(language); - - StateSet set; - if (map.TryGetValue(analyzer, out set)) - { - return set; - } - - return null; + return GetAnalyzerMap(language).GetStateSet(analyzer); } - private ImmutableDictionary GetAnalyzerMap(string language) + private DiagnosticAnalyzerMap GetAnalyzerMap(string language) { return ImmutableInterlocked.GetOrAdd(ref _stateMap, language, CreateLanguageSpecificAnalyzerMap, this); } - private ImmutableDictionary CreateLanguageSpecificAnalyzerMap(string language, HostStates @this) + private DiagnosticAnalyzerMap CreateLanguageSpecificAnalyzerMap(string language, HostStates @this) { var analyzersPerReference = _owner.AnalyzerManager.GetHostDiagnosticAnalyzersPerReference(language); var analyzerMap = CreateAnalyzerMap(_owner.AnalyzerManager, language, analyzersPerReference.Values); VerifyDiagnosticStates(analyzerMap.Values); - return analyzerMap; + return new DiagnosticAnalyzerMap(_owner.AnalyzerManager, language, analyzerMap); + } + + private class DiagnosticAnalyzerMap + { + private readonly DiagnosticAnalyzer _compilerAnalyzer; + private readonly StateSet _compilerStateSet; + + private readonly ImmutableDictionary _map; + + public DiagnosticAnalyzerMap(HostAnalyzerManager analyzerManager, string language, ImmutableDictionary analyzerMap) + { + // hold directly on to compiler analyzer + _compilerAnalyzer = analyzerManager.GetCompilerDiagnosticAnalyzer(language); + Contract.ThrowIfNull(_compilerAnalyzer); + + _compilerStateSet = analyzerMap[_compilerAnalyzer]; + + // hold rest of analyzers + _map = analyzerMap.Remove(_compilerAnalyzer); + } + + public IEnumerable GetStateSets() + { + // always return compiler one first + yield return _compilerStateSet; + + // TODO: for now, this is static, but in future, we might consider making this a dynamic so that we process cheaper analyzer first. + foreach (var set in _map.Values) + { + yield return set; + } + } + + public StateSet GetStateSet(DiagnosticAnalyzer analyzer) + { + if (_compilerAnalyzer == analyzer) + { + return _compilerStateSet; + } + + StateSet set; + if (_map.TryGetValue(analyzer, out set)) + { + return set; + } + + return null; + } } } }