diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerService.cs b/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerService.cs index 6a5dcdd285bed5dc18e46d6e409eee3c73da4b46..76aee5d1e59cec2a510b4b8deb4fdd3596b03366 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerService.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerService.cs @@ -64,7 +64,8 @@ internal sealed class TestDiagnosticAnalyzerService : DiagnosticAnalyzerService AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, PrimaryWorkspace primaryWorkspace, Action onAnalyzerException = null) - : base(SpecializedCollections.EmptyEnumerable(), null, hostDiagnosticUpdateSource, primaryWorkspace, new MockDiagnosticUpdateSourceRegistrationService()) + : base(new Lazy>(() => ImmutableArray.Empty), + hostAnalyzerAssemblyLoader: null, hostDiagnosticUpdateSource, primaryWorkspace, new MockDiagnosticUpdateSourceRegistrationService()) { _onAnalyzerException = onAnalyzerException; } diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs index 1e3758d2ecf7162429bc768a742f93e42d742c7f..156d58d4b1c335c54a74ba0b35cfd378d3d6a682 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService.cs @@ -29,7 +29,7 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService PrimaryWorkspace primaryWorkspace, [Import(AllowDefault = true)]IWorkspaceDiagnosticAnalyzerProviderService diagnosticAnalyzerProviderService = null, [Import(AllowDefault = true)]AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource = null) - : this(diagnosticAnalyzerProviderService != null ? diagnosticAnalyzerProviderService.GetHostDiagnosticAnalyzerPackages() : SpecializedCollections.EmptyEnumerable(), + : this(new Lazy>(() => GetHostDiagnosticAnalyzerPackage(diagnosticAnalyzerProviderService), isThreadSafe: true), diagnosticAnalyzerProviderService?.GetAnalyzerAssemblyLoader(), hostDiagnosticUpdateSource, primaryWorkspace, @@ -39,11 +39,9 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService // never be null } - public IAsynchronousOperationListener Listener => _listener; - // protected for testing purposes. protected DiagnosticAnalyzerService( - IEnumerable workspaceAnalyzerPackages, + Lazy> workspaceAnalyzerPackages, IAnalyzerAssemblyLoader hostAnalyzerAssemblyLoader, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, PrimaryWorkspace primaryWorkspace, @@ -53,6 +51,8 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService { } + public IAsynchronousOperationListener Listener => _listener; + // protected for testing purposes. protected DiagnosticAnalyzerService( HostAnalyzerManager hostAnalyzerManager, @@ -255,5 +255,10 @@ public bool ContainsDiagnostics(Workspace workspace, ProjectId projectId) AnalyzerHelper.OnAnalyzerException_NoTelemetryLogging(ex, analyzer, diagnostic, _hostDiagnosticUpdateSource, projectId); }; } + + private static ImmutableArray GetHostDiagnosticAnalyzerPackage(IWorkspaceDiagnosticAnalyzerProviderService diagnosticAnalyzerProviderService) + { + return (diagnosticAnalyzerProviderService?.GetHostDiagnosticAnalyzerPackages()).ToImmutableArrayOrEmpty(); + } } } diff --git a/src/Features/Core/Portable/Diagnostics/HostAnalyzerManager.cs b/src/Features/Core/Portable/Diagnostics/HostAnalyzerManager.cs index e497b375bbed7b5226b899cdfaccd36a411bf256..3e0e8770493bcd4b74040f4c9134ac936cde07c1 100644 --- a/src/Features/Core/Portable/Diagnostics/HostAnalyzerManager.cs +++ b/src/Features/Core/Portable/Diagnostics/HostAnalyzerManager.cs @@ -25,7 +25,7 @@ internal sealed partial class HostAnalyzerManager /// /// This contains vsix info on where comes from. /// - private readonly ImmutableArray _hostDiagnosticAnalyzerPackages; + private readonly Lazy> _hostDiagnosticAnalyzerPackages; /// /// Key is analyzer reference identity . @@ -76,24 +76,19 @@ internal sealed partial class HostAnalyzerManager /// private readonly ConditionalWeakTable> _descriptorCache; - public HostAnalyzerManager(IEnumerable hostAnalyzerPackages, IAnalyzerAssemblyLoader hostAnalyzerAssemblyLoader, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, PrimaryWorkspace primaryWorkspace) : - this(CreateAnalyzerReferencesFromPackages(hostAnalyzerPackages, new HostAnalyzerReferenceDiagnosticReporter(hostDiagnosticUpdateSource, primaryWorkspace), hostAnalyzerAssemblyLoader), - hostAnalyzerPackages.ToImmutableArrayOrEmpty(), hostDiagnosticUpdateSource) - { - } - - public HostAnalyzerManager(ImmutableArray hostAnalyzerReferences, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : - this(hostAnalyzerReferences, ImmutableArray.Empty, hostDiagnosticUpdateSource) + public HostAnalyzerManager(Lazy> hostAnalyzerPackages, IAnalyzerAssemblyLoader hostAnalyzerAssemblyLoader, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, PrimaryWorkspace primaryWorkspace) : + this(new Lazy>(() => CreateAnalyzerReferencesFromPackages(hostAnalyzerPackages.Value, new HostAnalyzerReferenceDiagnosticReporter(hostDiagnosticUpdateSource, primaryWorkspace), hostAnalyzerAssemblyLoader), isThreadSafe: true), + hostAnalyzerPackages, hostDiagnosticUpdateSource) { } private HostAnalyzerManager( - ImmutableArray hostAnalyzerReferences, ImmutableArray hostAnalyzerPackages, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) + Lazy> hostAnalyzerReferences, Lazy> hostAnalyzerPackages, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) { _hostDiagnosticAnalyzerPackages = hostAnalyzerPackages; _hostDiagnosticUpdateSource = hostDiagnosticUpdateSource; - _hostAnalyzerReferencesMap = new Lazy>(() => hostAnalyzerReferences.IsDefault ? ImmutableDictionary.Empty : CreateAnalyzerReferencesMap(hostAnalyzerReferences)); + _hostAnalyzerReferencesMap = new Lazy>(() => hostAnalyzerReferences.Value.IsDefaultOrEmpty ? ImmutableDictionary.Empty : CreateAnalyzerReferencesMap(hostAnalyzerReferences.Value), isThreadSafe: true); _hostDiagnosticAnalyzersPerLanguageMap = new ConcurrentDictionary>>(concurrencyLevel: 2, capacity: 2); _lazyHostDiagnosticAnalyzersPerReferenceMap = new Lazy>>(() => CreateDiagnosticAnalyzersPerReferenceMap(_hostAnalyzerReferencesMap.Value), isThreadSafe: true); @@ -101,8 +96,12 @@ internal sealed partial class HostAnalyzerManager _compilerDiagnosticAnalyzerDescriptorMap = ImmutableDictionary>.Empty; _hostDiagnosticAnalyzerPackageNameMap = ImmutableDictionary.Empty; _descriptorCache = new ConditionalWeakTable>(); + } - DiagnosticAnalyzerLogger.LogWorkspaceAnalyzers(hostAnalyzerReferences); + // this is for testing + internal HostAnalyzerManager(ImmutableArray hostAnalyzerReferences, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : + this(new Lazy>(() => hostAnalyzerReferences), new Lazy>(() => ImmutableArray.Empty), hostDiagnosticUpdateSource) + { } /// @@ -357,7 +356,7 @@ public string GetDiagnosticAnalyzerPackageName(string language, DiagnosticAnalyz private ImmutableDictionary CreateAnalyzerPathToPackageNameMap() { var builder = ImmutableDictionary.CreateBuilder(StringComparer.OrdinalIgnoreCase); - foreach (var package in _hostDiagnosticAnalyzerPackages) + foreach (var package in _hostDiagnosticAnalyzerPackages.Value) { if (string.IsNullOrEmpty(package.Name)) { @@ -444,11 +443,11 @@ private bool CheckAnalyzerReferenceIdentity(AnalyzerReference reference) } private static ImmutableArray CreateAnalyzerReferencesFromPackages( - IEnumerable analyzerPackages, + ImmutableArray analyzerPackages, HostAnalyzerReferenceDiagnosticReporter reporter, IAnalyzerAssemblyLoader hostAnalyzerAssemblyLoader) { - if (analyzerPackages == null || analyzerPackages.IsEmpty()) + if (analyzerPackages.IsEmpty) { return ImmutableArray.Empty; } @@ -466,7 +465,10 @@ private bool CheckAnalyzerReferenceIdentity(AnalyzerReference reference) builder.Add(reference); } - return builder.ToImmutable(); + var references = builder.ToImmutable(); + DiagnosticAnalyzerLogger.LogWorkspaceAnalyzers(references); + + return references; } private static ImmutableDictionary> MergeDiagnosticAnalyzerMap( diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs index dc6e37b327921b75f4687e785c16010d63007cc2..520be615d83728fb8bbdbad611606478d11dacdb 100644 --- a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs @@ -27,7 +27,7 @@ internal partial class VisualStudioWorkspaceDiagnosticAnalyzerProviderService : private const string AnalyzerContentTypeName = "Microsoft.VisualStudio.Analyzer"; - private readonly ImmutableArray _hostDiagnosticAnalyzerInfo; + private readonly Lazy> _hostDiagnosticAnalyzerInfo; /// /// Loader for VSIX-based analyzers. @@ -54,12 +54,13 @@ internal partial class VisualStudioWorkspaceDiagnosticAnalyzerProviderService : FailFast.OnFatalException(new Exception("extension manager can't be null")); } - _hostDiagnosticAnalyzerInfo = GetHostAnalyzerPackagesWithName(extensionManager, assembly.GetType("Microsoft.VisualStudio.ExtensionManager.IExtensionContent")); + _hostDiagnosticAnalyzerInfo = new Lazy>( + () => GetHostAnalyzerPackagesWithName(extensionManager, assembly.GetType("Microsoft.VisualStudio.ExtensionManager.IExtensionContent")), isThreadSafe: true); } public IEnumerable GetHostDiagnosticAnalyzerPackages() { - return _hostDiagnosticAnalyzerInfo; + return _hostDiagnosticAnalyzerInfo.Value; } public IAnalyzerAssemblyLoader GetAnalyzerAssemblyLoader() diff --git a/src/VisualStudio/Core/Test/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderServiceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderServiceTests.vb index 0ca512cbbc2ac87cd204680b2b5a47c1ccfeede1..5780bc67d27523c52397d73e92da8ab437d5a350 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderServiceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderServiceTests.vb @@ -50,9 +50,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim dir = tempRoot.CreateDirectory Dim analyzerFile = DesktopTestHelpers.CreateCSharpAnalyzerAssemblyWithTestAnalyzer(dir, "TestAnalyzer") Dim analyzerPackage = New HostDiagnosticAnalyzerPackage("MyPackage", ImmutableArray.Create(analyzerFile.Path)) - Dim analyzerPackages = SpecializedCollections.SingletonEnumerable(analyzerPackage) + Dim analyzerPackages = ImmutableArray.Create(analyzerPackage) Dim analyzerLoader = VisualStudioWorkspaceDiagnosticAnalyzerProviderService.GetLoader() - Dim hostAnalyzerManager = New HostAnalyzerManager(analyzerPackages, analyzerLoader, hostDiagnosticUpdateSource:=Nothing, primaryWorkspace:=Nothing) + Dim hostAnalyzerManager = New HostAnalyzerManager(New Lazy(Of ImmutableArray(Of HostDiagnosticAnalyzerPackage))( + Function() analyzerPackages), analyzerLoader, + hostDiagnosticUpdateSource:=Nothing, + primaryWorkspace:=Nothing) Dim analyzerReferenceMap = hostAnalyzerManager.GetHostDiagnosticAnalyzersPerReference(LanguageNames.CSharp) Assert.Single(analyzerReferenceMap) Dim analyzers = analyzerReferenceMap.Single().Value