未验证 提交 3765a2f2 编写于 作者: H Heejae Chang 提交者: GitHub

make diagnostic analyzer service lazy and not require UI thread. (#25982)

* make diagnostic analyzer service lazy and not require UI thread.

require ExtensionManager change that got checked into 15.8

* change location where we log number of workspace analyzer references due to it being lazy now.

* PR feedback
上级 ea1339f3
......@@ -64,7 +64,8 @@ internal sealed class TestDiagnosticAnalyzerService : DiagnosticAnalyzerService
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource,
PrimaryWorkspace primaryWorkspace,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
: base(SpecializedCollections.EmptyEnumerable<HostDiagnosticAnalyzerPackage>(), null, hostDiagnosticUpdateSource, primaryWorkspace, new MockDiagnosticUpdateSourceRegistrationService())
: base(new Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>>(() => ImmutableArray<HostDiagnosticAnalyzerPackage>.Empty),
hostAnalyzerAssemblyLoader: null, hostDiagnosticUpdateSource, primaryWorkspace, new MockDiagnosticUpdateSourceRegistrationService())
{
_onAnalyzerException = onAnalyzerException;
}
......
......@@ -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<HostDiagnosticAnalyzerPackage>(),
: this(new Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>>(() => 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<HostDiagnosticAnalyzerPackage> workspaceAnalyzerPackages,
Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>> 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<HostDiagnosticAnalyzerPackage> GetHostDiagnosticAnalyzerPackage(IWorkspaceDiagnosticAnalyzerProviderService diagnosticAnalyzerProviderService)
{
return (diagnosticAnalyzerProviderService?.GetHostDiagnosticAnalyzerPackages()).ToImmutableArrayOrEmpty();
}
}
}
......@@ -25,7 +25,7 @@ internal sealed partial class HostAnalyzerManager
/// <summary>
/// This contains vsix info on where <see cref="HostDiagnosticAnalyzerPackage"/> comes from.
/// </summary>
private readonly ImmutableArray<HostDiagnosticAnalyzerPackage> _hostDiagnosticAnalyzerPackages;
private readonly Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>> _hostDiagnosticAnalyzerPackages;
/// <summary>
/// Key is analyzer reference identity <see cref="GetAnalyzerReferenceIdentity(AnalyzerReference)"/>.
......@@ -76,24 +76,19 @@ internal sealed partial class HostAnalyzerManager
/// </summary>
private readonly ConditionalWeakTable<DiagnosticAnalyzer, IReadOnlyCollection<DiagnosticDescriptor>> _descriptorCache;
public HostAnalyzerManager(IEnumerable<HostDiagnosticAnalyzerPackage> hostAnalyzerPackages, IAnalyzerAssemblyLoader hostAnalyzerAssemblyLoader, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, PrimaryWorkspace primaryWorkspace) :
this(CreateAnalyzerReferencesFromPackages(hostAnalyzerPackages, new HostAnalyzerReferenceDiagnosticReporter(hostDiagnosticUpdateSource, primaryWorkspace), hostAnalyzerAssemblyLoader),
hostAnalyzerPackages.ToImmutableArrayOrEmpty(), hostDiagnosticUpdateSource)
{
}
public HostAnalyzerManager(ImmutableArray<AnalyzerReference> hostAnalyzerReferences, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) :
this(hostAnalyzerReferences, ImmutableArray<HostDiagnosticAnalyzerPackage>.Empty, hostDiagnosticUpdateSource)
public HostAnalyzerManager(Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>> hostAnalyzerPackages, IAnalyzerAssemblyLoader hostAnalyzerAssemblyLoader, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, PrimaryWorkspace primaryWorkspace) :
this(new Lazy<ImmutableArray<AnalyzerReference>>(() => CreateAnalyzerReferencesFromPackages(hostAnalyzerPackages.Value, new HostAnalyzerReferenceDiagnosticReporter(hostDiagnosticUpdateSource, primaryWorkspace), hostAnalyzerAssemblyLoader), isThreadSafe: true),
hostAnalyzerPackages, hostDiagnosticUpdateSource)
{
}
private HostAnalyzerManager(
ImmutableArray<AnalyzerReference> hostAnalyzerReferences, ImmutableArray<HostDiagnosticAnalyzerPackage> hostAnalyzerPackages, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
Lazy<ImmutableArray<AnalyzerReference>> hostAnalyzerReferences, Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>> hostAnalyzerPackages, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
{
_hostDiagnosticAnalyzerPackages = hostAnalyzerPackages;
_hostDiagnosticUpdateSource = hostDiagnosticUpdateSource;
_hostAnalyzerReferencesMap = new Lazy<ImmutableDictionary<object, AnalyzerReference>>(() => hostAnalyzerReferences.IsDefault ? ImmutableDictionary<object, AnalyzerReference>.Empty : CreateAnalyzerReferencesMap(hostAnalyzerReferences));
_hostAnalyzerReferencesMap = new Lazy<ImmutableDictionary<object, AnalyzerReference>>(() => hostAnalyzerReferences.Value.IsDefaultOrEmpty ? ImmutableDictionary<object, AnalyzerReference>.Empty : CreateAnalyzerReferencesMap(hostAnalyzerReferences.Value), isThreadSafe: true);
_hostDiagnosticAnalyzersPerLanguageMap = new ConcurrentDictionary<string, ImmutableDictionary<object, ImmutableArray<DiagnosticAnalyzer>>>(concurrencyLevel: 2, capacity: 2);
_lazyHostDiagnosticAnalyzersPerReferenceMap = new Lazy<ImmutableDictionary<object, ImmutableArray<DiagnosticAnalyzer>>>(() => CreateDiagnosticAnalyzersPerReferenceMap(_hostAnalyzerReferencesMap.Value), isThreadSafe: true);
......@@ -101,8 +96,12 @@ internal sealed partial class HostAnalyzerManager
_compilerDiagnosticAnalyzerDescriptorMap = ImmutableDictionary<DiagnosticAnalyzer, HashSet<string>>.Empty;
_hostDiagnosticAnalyzerPackageNameMap = ImmutableDictionary<DiagnosticAnalyzer, string>.Empty;
_descriptorCache = new ConditionalWeakTable<DiagnosticAnalyzer, IReadOnlyCollection<DiagnosticDescriptor>>();
}
DiagnosticAnalyzerLogger.LogWorkspaceAnalyzers(hostAnalyzerReferences);
// this is for testing
internal HostAnalyzerManager(ImmutableArray<AnalyzerReference> hostAnalyzerReferences, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) :
this(new Lazy<ImmutableArray<AnalyzerReference>>(() => hostAnalyzerReferences), new Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>>(() => ImmutableArray<HostDiagnosticAnalyzerPackage>.Empty), hostDiagnosticUpdateSource)
{
}
/// <summary>
......@@ -357,7 +356,7 @@ public string GetDiagnosticAnalyzerPackageName(string language, DiagnosticAnalyz
private ImmutableDictionary<string, string> CreateAnalyzerPathToPackageNameMap()
{
var builder = ImmutableDictionary.CreateBuilder<string, string>(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<AnalyzerReference> CreateAnalyzerReferencesFromPackages(
IEnumerable<HostDiagnosticAnalyzerPackage> analyzerPackages,
ImmutableArray<HostDiagnosticAnalyzerPackage> analyzerPackages,
HostAnalyzerReferenceDiagnosticReporter reporter,
IAnalyzerAssemblyLoader hostAnalyzerAssemblyLoader)
{
if (analyzerPackages == null || analyzerPackages.IsEmpty())
if (analyzerPackages.IsEmpty)
{
return ImmutableArray<AnalyzerReference>.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<object, ImmutableArray<DiagnosticAnalyzer>> MergeDiagnosticAnalyzerMap(
......
......@@ -27,7 +27,7 @@ internal partial class VisualStudioWorkspaceDiagnosticAnalyzerProviderService :
private const string AnalyzerContentTypeName = "Microsoft.VisualStudio.Analyzer";
private readonly ImmutableArray<HostDiagnosticAnalyzerPackage> _hostDiagnosticAnalyzerInfo;
private readonly Lazy<ImmutableArray<HostDiagnosticAnalyzerPackage>> _hostDiagnosticAnalyzerInfo;
/// <summary>
/// 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<ImmutableArray<HostDiagnosticAnalyzerPackage>>(
() => GetHostAnalyzerPackagesWithName(extensionManager, assembly.GetType("Microsoft.VisualStudio.ExtensionManager.IExtensionContent")), isThreadSafe: true);
}
public IEnumerable<HostDiagnosticAnalyzerPackage> GetHostDiagnosticAnalyzerPackages()
{
return _hostDiagnosticAnalyzerInfo;
return _hostDiagnosticAnalyzerInfo.Value;
}
public IAnalyzerAssemblyLoader GetAnalyzerAssemblyLoader()
......
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册