From 2e438ae3a09ba65bee8f3d3c6bd3b958eed605d2 Mon Sep 17 00:00:00 2001 From: Heejae Chang Date: Mon, 6 Apr 2015 18:30:18 -0700 Subject: [PATCH] added error source support now, error list will have column (which is off by default) that shows source of each errors in a format "assembly name" for analyzers node. and "assembly name" [vsix name] for vsix --- .../Squiggles/ErrorSquiggleProducerTests.cs | 5 +- ...agnosticsTagSource.DiagnosticsTagSource.cs | 2 +- .../EditAndContinueDiagnosticUpdateSource.cs | 15 +- .../TestDiagnosticAnalyzerService.cs | 2 +- ...mpilerDiagnosticAnalyzerProviderService.cs | 9 +- .../AbstractHostDiagnosticUpdateSource.cs | 30 +++- .../Core/Diagnostics/AnalyzerHelper.cs | 6 + .../Core/Diagnostics/AnalyzerUpdateArgsId.cs | 30 ++++ .../Diagnostics/DiagnosticAnalyzerService.cs | 20 ++- ...agnosticIncrementalAnalyzer.NestedTypes.cs | 30 +++- ...ementalAnalyzer.StateManager.HostStates.cs | 2 +- ...ntalAnalyzer.StateManager.ProjectStates.cs | 4 +- ...gnosticIncrementalAnalyzer.StateManager.cs | 20 ++- .../DiagnosticIncrementalAnalyzer.StateSet.cs | 5 +- .../EngineV1/DiagnosticIncrementalAnalyzer.cs | 71 +++++----- ...ncrementalAnalyzer_BuildSynchronization.cs | 4 +- .../Core/Diagnostics/ErrorSourceId.cs | 66 +++++++++ .../Core/Diagnostics/HostAnalyzerManager.cs | 128 ++++++++++++++++-- .../HostDiagnosticAnalyzerPackage.cs | 21 +++ .../Diagnostics/IDiagnosticAnalyzerService.cs | 10 ++ .../Core/Diagnostics/ISupportLiveUpdate.cs | 11 ++ ...kspaceDiagnosticAnalyzerProviderService.cs | 5 +- .../Diagnostics/PredefinedErrorSources.cs | 11 ++ src/Features/Core/Diagnostics/UpdateArgsId.cs | 33 ----- src/Features/Core/Features.csproj | 6 +- .../Core/FeaturesResources.Designer.cs | 27 ++++ src/Features/Core/FeaturesResources.resx | 9 ++ .../MiscellaneousDiagnosticAnalyzerService.cs | 29 +++- ...kspaceDiagnosticAnalyzerProviderService.cs | 30 +++- .../VisualStudioBaseDiagnosticListTable.cs | 8 +- .../ExternalErrorDiagnosticUpdateSource.cs | 20 +-- .../DiagnosticTableDataSourceTests.vb | 51 ++++++- .../ExternalDiagnosticUpdateSourceTests.vb | 8 ++ .../MiscDiagnosticUpdateSourceTests.vb | 45 +++++- .../EditAndContinueTestHelper.vb | 10 +- 35 files changed, 640 insertions(+), 143 deletions(-) create mode 100644 src/Features/Core/Diagnostics/AnalyzerUpdateArgsId.cs create mode 100644 src/Features/Core/Diagnostics/ErrorSourceId.cs create mode 100644 src/Features/Core/Diagnostics/HostDiagnosticAnalyzerPackage.cs create mode 100644 src/Features/Core/Diagnostics/ISupportLiveUpdate.cs create mode 100644 src/Features/Core/Diagnostics/PredefinedErrorSources.cs delete mode 100644 src/Features/Core/Diagnostics/UpdateArgsId.cs diff --git a/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs b/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs index 2a7e66a372d..bab8d4b6fe3 100644 --- a/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs +++ b/src/EditorFeatures/CSharpTest/Squiggles/ErrorSquiggleProducerTests.cs @@ -212,10 +212,9 @@ class Test } } - private class LiveId : UpdateArgsId + private class LiveId : ISupportLiveUpdate { - // use just a random analyzer - public LiveId() : base(new CSharpSimplifyTypeNamesDiagnosticAnalyzer()) + public LiveId() { } } diff --git a/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractAggregatedDiagnosticsTagSource.DiagnosticsTagSource.cs b/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractAggregatedDiagnosticsTagSource.DiagnosticsTagSource.cs index bff2f8ca7f9..79f179bbbfe 100644 --- a/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractAggregatedDiagnosticsTagSource.DiagnosticsTagSource.cs +++ b/src/EditorFeatures/Core/Implementation/Diagnostics/AbstractAggregatedDiagnosticsTagSource.DiagnosticsTagSource.cs @@ -111,7 +111,7 @@ public void AppendIntersectingSpans(int start, int length, IntervalIntrospector } // only follow minimum length for live diagnostic. otherwise, let it be zero length. - var minimumLegnth = _id is UpdateArgsId ? _owner.MinimumLength : 0; + var minimumLegnth = _id is ISupportLiveUpdate ? _owner.MinimumLength : 0; foreach (var data in result) { diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs index e1663396d2e..f251cf8baa1 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs @@ -94,7 +94,7 @@ private static DiagnosticData MakeDiagnosticData(ProjectId projectId, Document d DebuggingSession session, object errorId, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray items) { return new DiagnosticsUpdatedArgs( - id: Tuple.Create(session, errorId), + id: new EnCId(session, errorId), workspace: workspace, solution: solution, projectId: projectId, @@ -110,5 +110,18 @@ private void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) updated(this, args); } } + + private class EnCId : ErrorSourceId.Base + { + public EnCId(DebuggingSession session, object errorId) : + base(session, errorId) + { + } + + public override string ErrorSource + { + get { return PredefinedErrorSources.EnC; } + } + } } } diff --git a/src/EditorFeatures/Test/Diagnostics/TestDiagnosticAnalyzerService.cs b/src/EditorFeatures/Test/Diagnostics/TestDiagnosticAnalyzerService.cs index 9118c5f918e..b3616833213 100644 --- a/src/EditorFeatures/Test/Diagnostics/TestDiagnosticAnalyzerService.cs +++ b/src/EditorFeatures/Test/Diagnostics/TestDiagnosticAnalyzerService.cs @@ -30,7 +30,7 @@ internal TestDiagnosticAnalyzerService(ImmutableDictionary onAnalyzerException = null) - : base(workspaceAnalyzerAssemblies: SpecializedCollections.EmptyEnumerable(), hostDiagnosticUpdateSource: hostDiagnosticUpdateSource) + : base(SpecializedCollections.EmptyEnumerable(), hostDiagnosticUpdateSource) { _onAnalyzerException = onAnalyzerException; } diff --git a/src/EditorFeatures/Test/Preview/TestOnly_CompilerDiagnosticAnalyzerProviderService.cs b/src/EditorFeatures/Test/Preview/TestOnly_CompilerDiagnosticAnalyzerProviderService.cs index 14cc780b7cb..5555e9cedd0 100644 --- a/src/EditorFeatures/Test/Preview/TestOnly_CompilerDiagnosticAnalyzerProviderService.cs +++ b/src/EditorFeatures/Test/Preview/TestOnly_CompilerDiagnosticAnalyzerProviderService.cs @@ -1,6 +1,7 @@ // 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 System.Collections.Generic; +using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Linq; using Microsoft.CodeAnalysis; @@ -11,12 +12,12 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.Preview [Export(typeof(IWorkspaceDiagnosticAnalyzerProviderService))] internal class TestOnly_CompilerDiagnosticAnalyzerProviderService : IWorkspaceDiagnosticAnalyzerProviderService { - private readonly IEnumerable _compilerAnalyzerAssemblies; + private readonly HostDiagnosticAnalyzerPackage _info; [ImportingConstructor] public TestOnly_CompilerDiagnosticAnalyzerProviderService() { - _compilerAnalyzerAssemblies = GetCompilerAnalyzerAssemblies().Distinct(); + _info = new HostDiagnosticAnalyzerPackage("Compiler", GetCompilerAnalyzerAssemblies().Distinct().ToImmutableArray()); } private static IEnumerable GetCompilerAnalyzerAssemblies() @@ -31,9 +32,9 @@ private static IEnumerable GetCompilerAnalyzerAssemblies() } } - public IEnumerable GetWorkspaceAnalyzerAssemblies() + public IEnumerable GetHostDiagnosticAnalyzerPackages() { - return _compilerAnalyzerAssemblies; + yield return _info; } } } diff --git a/src/Features/Core/Diagnostics/AbstractHostDiagnosticUpdateSource.cs b/src/Features/Core/Diagnostics/AbstractHostDiagnosticUpdateSource.cs index c731bb1160c..e2a110c61bf 100644 --- a/src/Features/Core/Diagnostics/AbstractHostDiagnosticUpdateSource.cs +++ b/src/Features/Core/Diagnostics/AbstractHostDiagnosticUpdateSource.cs @@ -124,7 +124,7 @@ private void ClearAnalyzerDiagnostics(DiagnosticAnalyzer analyzer, ProjectId pro private DiagnosticsUpdatedArgs MakeArgs(DiagnosticAnalyzer analyzer, ImmutableHashSet items, Project project) { return new DiagnosticsUpdatedArgs( - id: Tuple.Create(this, analyzer, project?.Id), + id: new HostArgsId(this, analyzer, project?.Id), workspace: this.Workspace, solution: project?.Solution, projectId: project?.Id, @@ -142,5 +142,33 @@ internal ImmutableHashSet TestOnly_GetReportedDiagnostics(Diagno return diagnostics; } + + private class HostArgsId : AnalyzerUpdateArgsId + { + private readonly AbstractHostDiagnosticUpdateSource _source; + private readonly ProjectId _projectId; + + public HostArgsId(AbstractHostDiagnosticUpdateSource source, DiagnosticAnalyzer analyzer, ProjectId id) : base(analyzer) + { + this._source = source; + this._projectId = id; + } + + public override bool Equals(object obj) + { + var other = obj as HostArgsId; + if (other == null) + { + return false; + } + + return _source == other._source && _projectId == other._projectId && base.Equals(obj); + } + + public override int GetHashCode() + { + return Hash.Combine(_source.GetHashCode(), Hash.Combine(_projectId.GetHashCode(), base.GetHashCode())); + } + } } } diff --git a/src/Features/Core/Diagnostics/AnalyzerHelper.cs b/src/Features/Core/Diagnostics/AnalyzerHelper.cs index 1d932589197..a1fb1d28889 100644 --- a/src/Features/Core/Diagnostics/AnalyzerHelper.cs +++ b/src/Features/Core/Diagnostics/AnalyzerHelper.cs @@ -43,6 +43,12 @@ public static bool IsCompilerAnalyzer(this DiagnosticAnalyzer analyzer) return ValueTuple.Create(GetAssemblyQualifiedNameWithoutVersion(type), GetAnalyzerVersion(type.Assembly.Location)); } + public static string GetAnalyzerAssemblyName(this DiagnosticAnalyzer analyzer) + { + var type = analyzer.GetType(); + return type.Assembly.GetName().Name; + } + private static string GetAssemblyQualifiedNameWithoutVersion(Type type) { var name = type.AssemblyQualifiedName; diff --git a/src/Features/Core/Diagnostics/AnalyzerUpdateArgsId.cs b/src/Features/Core/Diagnostics/AnalyzerUpdateArgsId.cs new file mode 100644 index 00000000000..f9f4d4baa90 --- /dev/null +++ b/src/Features/Core/Diagnostics/AnalyzerUpdateArgsId.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + /// + /// Base type of a type that is used as for live diagnostic + /// + internal class AnalyzerUpdateArgsId : ErrorSourceId.Base, ISupportLiveUpdate + { + public DiagnosticAnalyzer Analyzer => _Field1; + + protected AnalyzerUpdateArgsId(DiagnosticAnalyzer analyzer) : + base(analyzer) + { + } + + public override string ErrorSource + { + get + { + if (Analyzer == null) + { + return string.Empty; + } + + return Analyzer.GetAnalyzerAssemblyName(); + } + } + } +} diff --git a/src/Features/Core/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/Core/Diagnostics/DiagnosticAnalyzerService.cs index cc31400f893..9520b2bd727 100644 --- a/src/Features/Core/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/Core/Diagnostics/DiagnosticAnalyzerService.cs @@ -27,10 +27,8 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService [ImportMany] IEnumerable> asyncListeners, [Import(AllowDefault = true)]IWorkspaceDiagnosticAnalyzerProviderService diagnosticAnalyzerProviderService = null, [Import(AllowDefault = true)]AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource = null) - : this(workspaceAnalyzerAssemblies: diagnosticAnalyzerProviderService != null ? - diagnosticAnalyzerProviderService.GetWorkspaceAnalyzerAssemblies() : - SpecializedCollections.EmptyEnumerable(), - hostDiagnosticUpdateSource: hostDiagnosticUpdateSource) + : this(diagnosticAnalyzerProviderService != null ? diagnosticAnalyzerProviderService.GetHostDiagnosticAnalyzerPackages() : SpecializedCollections.EmptyEnumerable(), + hostDiagnosticUpdateSource) { _listener = new AggregateAsynchronousOperationListener(asyncListeners, FeatureAttribute.DiagnosticService); } @@ -38,9 +36,9 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService public IAsynchronousOperationListener Listener => _listener; // protected for testing purposes. - protected DiagnosticAnalyzerService(IEnumerable workspaceAnalyzerAssemblies, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : this() + protected DiagnosticAnalyzerService(IEnumerable workspaceAnalyzerPackages, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : this() { - _hostAnalyzerManager = new HostAnalyzerManager(workspaceAnalyzerAssemblies, hostDiagnosticUpdateSource); + _hostAnalyzerManager = new HostAnalyzerManager(workspaceAnalyzerPackages, hostDiagnosticUpdateSource); _hostDiagnosticUpdateSource = hostDiagnosticUpdateSource; } @@ -174,6 +172,16 @@ public bool IsCompilerDiagnostic(string language, DiagnosticData diagnostic) return _hostAnalyzerManager.IsCompilerDiagnostic(language, diagnostic); } + public DiagnosticAnalyzer GetCompilerDiagnosticAnalyzer(string language) + { + return _hostAnalyzerManager.GetCompilerDiagnosticAnalyzer(language); + } + + public bool IsCompilerDiagnosticAnalyzer(string language, DiagnosticAnalyzer analyzer) + { + return _hostAnalyzerManager.IsCompilerDiagnosticAnalyzer(language, analyzer); + } + // virtual for testing purposes. internal virtual Action GetOnAnalyzerException(ProjectId projectId, DiagnosticLogAggregator diagnosticLogAggregator) { diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.NestedTypes.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.NestedTypes.cs index d2b0709c0d2..88c49c601db 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.NestedTypes.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.NestedTypes.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 System; using System.Collections.Immutable; using Roslyn.Utilities; @@ -81,14 +82,33 @@ public VersionArgument(VersionStamp textVersion, VersionStamp dataVersion, Versi } } - public class ArgumentKey : UpdateArgsId + public class HostAnalyzerKey : ArgumentKey + { + private readonly string _analyzerPackageName; + + public HostAnalyzerKey(DiagnosticAnalyzer analyzer, StateType stateType, object key, string analyzerPackageName) : + base(analyzer, stateType, key) + { + _analyzerPackageName = analyzerPackageName; + } + + public override string ErrorSource + { + get + { + return _analyzerPackageName; + } + } + } + + public class ArgumentKey : AnalyzerUpdateArgsId { public readonly StateType StateType; public readonly object Key; - public ArgumentKey(DiagnosticAnalyzer analyzer, StateType stateTypeId, object key) : base(analyzer) + public ArgumentKey(DiagnosticAnalyzer analyzer, StateType stateType, object key) : base(analyzer) { - this.StateType = stateTypeId; + this.StateType = stateType; this.Key = key; } @@ -100,12 +120,12 @@ public override bool Equals(object obj) return false; } - return base.Equals(obj) && StateType == other.StateType && Key == other.Key; + return StateType == other.StateType && Key == other.Key && base.Equals(obj); } public override int GetHashCode() { - return Hash.Combine(Key, Hash.Combine(base.GetHashCode(), (int)StateType)); + return Hash.Combine(Key, Hash.Combine((int)StateType, base.GetHashCode())); } } } diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs index 2f32e582fd7..1ee624698d7 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.HostStates.cs @@ -58,7 +58,7 @@ public StateSet GetOrCreateStateSet(string language, DiagnosticAnalyzer analyzer { var analyzersPerReference = _owner.AnalyzerManager.GetHostDiagnosticAnalyzersPerReference(language); - var analyzerMap = CreateAnalyzerMap(language, analyzersPerReference.Values); + var analyzerMap = CreateAnalyzerMap(_owner.AnalyzerManager, language, analyzersPerReference.Values); VerifyDiagnosticStates(analyzerMap.Values); return analyzerMap; diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs index 6f171aa17ca..c6f5672ac7c 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.ProjectStates.cs @@ -78,7 +78,7 @@ public void RemoveStateSet(ProjectId projectId) } var newAnalyzersPerReference = _owner.AnalyzerManager.CreateProjectDiagnosticAnalyzersPerReference(project); - var newMap = StateManager.CreateAnalyzerMap(project.Language, newAnalyzersPerReference.Values); + var newMap = StateManager.CreateAnalyzerMap(_owner.AnalyzerManager, project.Language, newAnalyzersPerReference.Values); RaiseProjectAnalyzerReferenceChangedIfNeeded(project, newAnalyzersPerReference, newMap); @@ -135,7 +135,7 @@ public void RemoveStateSet(ProjectId projectId) return ImmutableDictionary.Empty; } - return StateManager.CreateAnalyzerMap(project.Language, analyzersPerReference.Values); + return StateManager.CreateAnalyzerMap(_owner.AnalyzerManager, project.Language, analyzersPerReference.Values); } private void RaiseProjectAnalyzerReferenceChangedIfNeeded( diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs index ff020f80965..a99b117e850 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateManager.cs @@ -112,8 +112,10 @@ private void RaiseProjectAnalyzerReferenceChanged(ProjectAnalyzerReferenceChange } private static ImmutableDictionary CreateAnalyzerMap( - string language, IEnumerable> analyzerCollection) + HostAnalyzerManager analyzerManager, string language, IEnumerable> analyzerCollection) { + var compilerAnalyzer = analyzerManager.GetCompilerDiagnosticAnalyzer(language); + var builder = ImmutableDictionary.CreateBuilder(); foreach (var analyzers in analyzerCollection) { @@ -128,13 +130,27 @@ private void RaiseProjectAnalyzerReferenceChanged(ProjectAnalyzerReferenceChange continue; } - builder.Add(analyzer, new StateSet(language, analyzer)); + var errorSourceName = analyzer == compilerAnalyzer ? + PredefinedErrorSources.Compiler : GetErrorSourceName(analyzerManager, language, analyzer); + + builder.Add(analyzer, new StateSet(language, analyzer, errorSourceName)); } } return builder.ToImmutable(); } + private static string GetErrorSourceName(HostAnalyzerManager analyzerManager, string language, DiagnosticAnalyzer analyzer) + { + var packageName = analyzerManager.GetDiagnosticAnalyzerPackageName(language, analyzer); + if (packageName == null) + { + return null; + } + + return $"{analyzer.GetAnalyzerAssemblyName()} [{packageName}]"; + } + [Conditional("DEBUG")] private static void VerifyDiagnosticStates(IEnumerable stateSets) { diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateSet.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateSet.cs index 36ff99da51e..4cd775af2d9 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateSet.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.StateSet.cs @@ -17,17 +17,20 @@ private class StateSet private readonly string _language; private readonly DiagnosticAnalyzer _analyzer; + private readonly string _errorSourceName; private readonly DiagnosticState[] _state; - public StateSet(string language, DiagnosticAnalyzer analyzer) + public StateSet(string language, DiagnosticAnalyzer analyzer, string errorSourceName) { _language = language; _analyzer = analyzer; + _errorSourceName = errorSourceName; _state = CreateDiagnosticStates(language, analyzer); } + public string ErrorSourceName => _errorSourceName; public string Language => _language; public DiagnosticAnalyzer Analyzer => _analyzer; diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs index 0aa39713453..f9e13de2246 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer.cs @@ -138,14 +138,14 @@ private async Task AnalyzeSyntaxAsync(Document document, ImmutableHashSet var data = await _executor.GetProjectAnalysisDataAsync(analyzerDriver, stateSet, versions).ConfigureAwait(false); if (data.FromCache) { - RaiseProjectDiagnosticsUpdated(project, stateSet.Analyzer, data.Items); + RaiseProjectDiagnosticsUpdated(project, stateSet, data.Items); continue; } var state = stateSet.GetState(StateType.Project); await PersistProjectData(project, state, data).ConfigureAwait(false); - RaiseProjectDiagnosticsUpdatedIfNeeded(project, stateSet.Analyzer, data.OldItems, data.Items); + RaiseProjectDiagnosticsUpdatedIfNeeded(project, stateSet, data.OldItems, data.Items); } } } @@ -385,7 +385,7 @@ public override void RemoveDocument(DocumentId documentId) var solutionArgs = new SolutionArgument(null, documentId.ProjectId, documentId); for (var stateType = 0; stateType < s_stateTypeCount; stateType++) { - RaiseDiagnosticsUpdated((StateType)stateType, documentId, stateSet.Analyzer, solutionArgs, ImmutableArray.Empty); + RaiseDiagnosticsUpdated((StateType)stateType, documentId, stateSet, solutionArgs, ImmutableArray.Empty); } } } @@ -400,7 +400,7 @@ public override void RemoveProject(ProjectId projectId) stateSet.Remove(projectId); var solutionArgs = new SolutionArgument(null, projectId, null); - RaiseDiagnosticsUpdated(StateType.Project, projectId, stateSet.Analyzer, solutionArgs, ImmutableArray.Empty); + RaiseDiagnosticsUpdated(StateType.Project, projectId, stateSet, solutionArgs, ImmutableArray.Empty); } } @@ -517,7 +517,7 @@ private static bool CheckSemanticVersions(Project project, AnalysisData existing } private void RaiseDocumentDiagnosticsUpdatedIfNeeded( - StateType type, Document document, DiagnosticAnalyzer analyzer, ImmutableArray existingItems, ImmutableArray newItems) + StateType type, Document document, StateSet stateSet, ImmutableArray existingItems, ImmutableArray newItems) { var noItems = existingItems.Length == 0 && newItems.Length == 0; if (noItems) @@ -525,11 +525,11 @@ private static bool CheckSemanticVersions(Project project, AnalysisData existing return; } - RaiseDiagnosticsUpdated(type, document.Id, analyzer, new SolutionArgument(document), newItems); + RaiseDiagnosticsUpdated(type, document.Id, stateSet, new SolutionArgument(document), newItems); } private void RaiseProjectDiagnosticsUpdatedIfNeeded( - Project project, DiagnosticAnalyzer analyzer, ImmutableArray existingItems, ImmutableArray newItems) + Project project, StateSet stateSet, ImmutableArray existingItems, ImmutableArray newItems) { var noItems = existingItems.Length == 0 && newItems.Length == 0; if (noItems) @@ -537,12 +537,12 @@ private static bool CheckSemanticVersions(Project project, AnalysisData existing return; } - RaiseProjectDiagnosticsRemovedIfNeeded(project, analyzer, existingItems, newItems); - RaiseProjectDiagnosticsUpdated(project, analyzer, newItems); + RaiseProjectDiagnosticsRemovedIfNeeded(project, stateSet, existingItems, newItems); + RaiseProjectDiagnosticsUpdated(project, stateSet, newItems); } private void RaiseProjectDiagnosticsRemovedIfNeeded( - Project project, DiagnosticAnalyzer analyzer, ImmutableArray existingItems, ImmutableArray newItems) + Project project, StateSet stateSet, ImmutableArray existingItems, ImmutableArray newItems) { if (existingItems.Length == 0) { @@ -554,28 +554,28 @@ private static bool CheckSemanticVersions(Project project, AnalysisData existing { if (documentId == null) { - RaiseDiagnosticsUpdated(StateType.Project, project.Id, analyzer, new SolutionArgument(project), ImmutableArray.Empty); + RaiseDiagnosticsUpdated(StateType.Project, project.Id, stateSet, new SolutionArgument(project), ImmutableArray.Empty); continue; } var document = project.GetDocument(documentId); var argument = documentId == null ? new SolutionArgument(null, documentId.ProjectId, documentId) : new SolutionArgument(document); - RaiseDiagnosticsUpdated(StateType.Project, documentId, analyzer, argument, ImmutableArray.Empty); + RaiseDiagnosticsUpdated(StateType.Project, documentId, stateSet, argument, ImmutableArray.Empty); } } - private void RaiseProjectDiagnosticsUpdated(Project project, DiagnosticAnalyzer analyzer, ImmutableArray diagnostics) + private void RaiseProjectDiagnosticsUpdated(Project project, StateSet stateSet, ImmutableArray diagnostics) { var group = diagnostics.GroupBy(d => d.DocumentId); foreach (var kv in group) { if (kv.Key == null) { - RaiseDiagnosticsUpdated(StateType.Project, project.Id, analyzer, new SolutionArgument(project), kv.ToImmutableArrayOrEmpty()); + RaiseDiagnosticsUpdated(StateType.Project, project.Id, stateSet, new SolutionArgument(project), kv.ToImmutableArrayOrEmpty()); continue; } - RaiseDiagnosticsUpdated(StateType.Project, kv.Key, analyzer, new SolutionArgument(project.GetDocument(kv.Key)), kv.ToImmutableArrayOrEmpty()); + RaiseDiagnosticsUpdated(StateType.Project, kv.Key, stateSet, new SolutionArgument(project.GetDocument(kv.Key)), kv.ToImmutableArrayOrEmpty()); } } @@ -585,14 +585,17 @@ private static ImmutableArray GetDiagnosticData(ILookup diagnostics) + StateType type, object key, StateSet stateSet, SolutionArgument solution, ImmutableArray diagnostics) { if (Owner == null) { return; } - var id = new ArgumentKey(analyzer, type, key); + // get right arg id for the given analyzer + var id = stateSet.ErrorSourceName != null ? + (object)new HostAnalyzerKey(stateSet.Analyzer, type, key, stateSet.ErrorSourceName) : (object)new ArgumentKey(stateSet.Analyzer, type, key); + Owner.RaiseDiagnosticsUpdated(this, new DiagnosticsUpdatedArgs(id, Workspace, solution.Solution, solution.ProjectId, solution.DocumentId, diagnostics)); } @@ -815,13 +818,15 @@ private void ClearDocumentStates(Document document, IEnumerable states for (var stateType = 0; stateType < s_stateTypeCount; stateType++) { cancellationToken.ThrowIfCancellationRequested(); - ClearDocumentState(document, state.Analyzer, (StateType)stateType, state.GetState((StateType)stateType), raiseEvent); + ClearDocumentState(document, state, (StateType)stateType, raiseEvent); } } } - private void ClearDocumentState(Document document, DiagnosticAnalyzer analyzer, StateType type, DiagnosticState state, bool raiseEvent) + private void ClearDocumentState(Document document, StateSet stateSet, StateType type, bool raiseEvent) { + var state = stateSet.GetState(type); + // remove saved info state.Remove(document.Id); @@ -831,7 +836,7 @@ private void ClearDocumentState(Document document, DiagnosticAnalyzer analyzer, var documentId = document.Id; var solutionArgs = new SolutionArgument(document); - RaiseDiagnosticsUpdated(type, document.Id, analyzer, solutionArgs, ImmutableArray.Empty); + RaiseDiagnosticsUpdated(type, document.Id, stateSet, solutionArgs, ImmutableArray.Empty); } } @@ -842,21 +847,23 @@ private void ClearProjectStatesAsync(Project project, IEnumerable stat ClearDocumentStates(document, states, raiseEvent: true, cancellationToken: cancellationToken); } - foreach (var state in states) + foreach (var stateSet in states) { cancellationToken.ThrowIfCancellationRequested(); - ClearProjectState(project, state.Analyzer, state.GetState(StateType.Project)); + ClearProjectState(project, stateSet); } } - private void ClearProjectState(Project project, DiagnosticAnalyzer analyzer, DiagnosticState state) + private void ClearProjectState(Project project, StateSet stateSet) { + var state = stateSet.GetState(StateType.Project); + // remove saved cache state.Remove(project.Id); // raise diagnostic updated event var solutionArgs = new SolutionArgument(project); - RaiseDiagnosticsUpdated(StateType.Project, project.Id, analyzer, solutionArgs, ImmutableArray.Empty); + RaiseDiagnosticsUpdated(StateType.Project, project.Id, stateSet, solutionArgs, ImmutableArray.Empty); } private async Task HandleSuppressedAnalyzerAsync(Document document, StateSet stateSet, StateType type, CancellationToken cancellationToken) @@ -865,7 +872,7 @@ private async Task HandleSuppressedAnalyzerAsync(Document document, StateSet sta var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); if (existingData?.Items.Length > 0) { - ClearDocumentState(document, stateSet.Analyzer, type, state, raiseEvent: true); + ClearDocumentState(document, stateSet, type, raiseEvent: true); } } @@ -875,7 +882,7 @@ private async Task HandleSuppressedAnalyzerAsync(Project project, StateSet state var existingData = await state.TryGetExistingDataAsync(project, cancellationToken).ConfigureAwait(false); if (existingData?.Items.Length > 0) { - ClearProjectState(project, stateSet.Analyzer, state); + ClearProjectState(project, stateSet); } } diff --git a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs index 21840e7c17d..497141e0426 100644 --- a/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs +++ b/src/Features/Core/Diagnostics/EngineV1/DiagnosticIncrementalAnalyzer_BuildSynchronization.cs @@ -39,7 +39,7 @@ public override async Task SynchronizeWithBuildAsync(Project project, ImmutableA var mergedDiagnostics = MergeDiagnostics(liveDiagnostics, GetExistingDiagnostics(existingDiagnostics)); await state.PersistAsync(project, new AnalysisData(projectTextVersion, semanticVersion, mergedDiagnostics), CancellationToken.None).ConfigureAwait(false); - RaiseDiagnosticsUpdated(StateType.Project, project.Id, stateSet.Analyzer, new SolutionArgument(project), mergedDiagnostics); + RaiseDiagnosticsUpdated(StateType.Project, project.Id, stateSet, new SolutionArgument(project), mergedDiagnostics); } } } @@ -105,7 +105,7 @@ private bool PreferLiveErrorsOnOpenedFiles(Workspace workspace) var mergedDiagnostics = MergeDiagnostics(diagnostics, GetExistingDiagnostics(existingDiagnostics)); await state.PersistAsync(document, new AnalysisData(textVersion, semanticVersion, mergedDiagnostics), CancellationToken.None).ConfigureAwait(false); - RaiseDiagnosticsUpdated(stateType, document.Id, stateSet.Analyzer, new SolutionArgument(document), mergedDiagnostics); + RaiseDiagnosticsUpdated(stateType, document.Id, stateSet, new SolutionArgument(document), mergedDiagnostics); } private static ImmutableArray GetExistingDiagnostics(AnalysisData analysisData) diff --git a/src/Features/Core/Diagnostics/ErrorSourceId.cs b/src/Features/Core/Diagnostics/ErrorSourceId.cs new file mode 100644 index 00000000000..29819ac3be2 --- /dev/null +++ b/src/Features/Core/Diagnostics/ErrorSourceId.cs @@ -0,0 +1,66 @@ +// 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; + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + /// + /// Support ErrorSource information. + /// + internal abstract class ErrorSourceId + { + public abstract string ErrorSource { get; } + + internal abstract class Base : ErrorSourceId + { + protected readonly T _Field1; + + public Base(T field) + { + _Field1 = field; + } + + public override bool Equals(object obj) + { + var other = obj as Base; + if (other == null) + { + return false; + } + + return object.Equals(_Field1, other._Field1); + } + + public override int GetHashCode() + { + return _Field1?.GetHashCode() ?? 0; + } + } + + internal abstract class Base : Base + { + private readonly T1 _Field2; + + public Base(T1 field1, T2 field2) : base(field2) + { + _Field2 = field1; + } + + public override bool Equals(object obj) + { + var other = obj as Base; + if (other == null) + { + return false; + } + + return object.Equals(_Field2, other._Field2) && base.Equals(other); + } + + public override int GetHashCode() + { + return Hash.Combine(_Field2?.GetHashCode() ?? 0, base.GetHashCode()); + } + } + } +} diff --git a/src/Features/Core/Diagnostics/HostAnalyzerManager.cs b/src/Features/Core/Diagnostics/HostAnalyzerManager.cs index c7841d17a52..fcd387d2fc7 100644 --- a/src/Features/Core/Diagnostics/HostAnalyzerManager.cs +++ b/src/Features/Core/Diagnostics/HostAnalyzerManager.cs @@ -4,10 +4,8 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; using System.Linq; using System.Reflection; -using System.Threading; using Microsoft.CodeAnalysis.Diagnostics.Log; using Roslyn.Utilities; @@ -24,6 +22,11 @@ namespace Microsoft.CodeAnalysis.Diagnostics /// internal sealed partial class HostAnalyzerManager { + /// + /// This contains vsix info on where comes from. + /// + private readonly ImmutableArray _hostDiagnosticAnalyzerPackages; + /// /// Key is analyzer reference identity . /// @@ -31,6 +34,11 @@ internal sealed partial class HostAnalyzerManager /// private readonly ImmutableDictionary _hostAnalyzerReferencesMap; + /// + /// Map contains to . + /// + private readonly ImmutableDictionary _hostAnalyzerReferenceNameMap; + /// /// Key is the language the supports and key for the second map is analyzer reference identity and /// for that assembly reference. @@ -58,18 +66,30 @@ internal sealed partial class HostAnalyzerManager /// private ImmutableDictionary _compilerDiagnosticAnalyzerMap; + /// + /// map from host diagnostic analyzer to package name it came from + /// + private ImmutableDictionary _hostDiagnosticAnalzyerPackageNameMap; + /// /// map to compiler diagnostic analyzer descriptor. /// private ImmutableDictionary> _compilerDiagnosticAnalyzerDescriptorMap; - public HostAnalyzerManager(IEnumerable hostAnalyzerAssemblies, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : - this(CreateAnalyzerReferencesFromAssemblies(hostAnalyzerAssemblies), hostDiagnosticUpdateSource) + public HostAnalyzerManager(IEnumerable hostAnalyzerPackages, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : + this(CreateAnalyzerReferencesFromPackages(hostAnalyzerPackages), hostAnalyzerPackages.ToImmutableArrayOrEmpty(), hostDiagnosticUpdateSource) { } - public HostAnalyzerManager(ImmutableArray hostAnalyzerReferences, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) + public HostAnalyzerManager(ImmutableArray hostAnalyzerReferences, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) : + this(hostAnalyzerReferences, ImmutableArray.Empty, hostDiagnosticUpdateSource) { + } + + private HostAnalyzerManager( + ImmutableArray hostAnalyzerReferences, ImmutableArray hostAnalyzerPackages, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) + { + _hostDiagnosticAnalyzerPackages = hostAnalyzerPackages; _hostDiagnosticUpdateSource = hostDiagnosticUpdateSource; _hostAnalyzerReferencesMap = hostAnalyzerReferences.IsDefault ? ImmutableDictionary.Empty : CreateAnalyzerReferencesMap(hostAnalyzerReferences); @@ -78,6 +98,7 @@ public HostAnalyzerManager(ImmutableArray hostAnalyzerReferen _compilerDiagnosticAnalyzerMap = ImmutableDictionary.Empty; _compilerDiagnosticAnalyzerDescriptorMap = ImmutableDictionary>.Empty; + _hostDiagnosticAnalzyerPackageNameMap = ImmutableDictionary.Empty; DiagnosticAnalyzerLogger.LogWorkspaceAnalyzers(hostAnalyzerReferences); } @@ -104,7 +125,7 @@ public ImmutableArray GetDiagnosticDescriptors(DiagnosticA /// public ImmutableDictionary> GetHostDiagnosticAnalyzersPerReference(string language) { - return _hostDiagnosticAnalyzersPerLanguageMap.GetOrAdd(language, CreateHostDiagnosticAnalyzers); + return _hostDiagnosticAnalyzersPerLanguageMap.GetOrAdd(language, CreateHostDiagnosticAnalyzersAndBuildMap); } /// @@ -172,6 +193,49 @@ public bool IsCompilerDiagnostic(string language, DiagnosticData diagnostic) return false; } + /// + /// Return compiler for the given language. + /// + public DiagnosticAnalyzer GetCompilerDiagnosticAnalyzer(string language) + { + var map = GetHostDiagnosticAnalyzersPerReference(language); + + DiagnosticAnalyzer compilerAnalyzer; + if (_compilerDiagnosticAnalyzerMap.TryGetValue(language, out compilerAnalyzer)) + { + return compilerAnalyzer; + } + + return null; + } + + /// + /// Check whether given is compiler analyzer for the language or not. + /// + public bool IsCompilerDiagnosticAnalyzer(string language, DiagnosticAnalyzer analyzer) + { + var map = GetHostDiagnosticAnalyzersPerReference(language); + + DiagnosticAnalyzer compilerAnalyzer; + return _compilerDiagnosticAnalyzerMap.TryGetValue(language, out compilerAnalyzer) && compilerAnalyzer == analyzer; + } + + /// + /// Get Name of Package (vsix) which Host is from. + /// + public string GetDiagnosticAnalyzerPackageName(string language, DiagnosticAnalyzer analyzer) + { + var map = GetHostDiagnosticAnalyzersPerReference(language); + + string name; + if (_hostDiagnosticAnalzyerPackageNameMap.TryGetValue(analyzer, out name)) + { + return name; + } + + return null; + } + private ImmutableDictionary> CreateDiagnosticDescriptorsPerReference( ImmutableDictionary> analyzersMap) { @@ -195,10 +259,12 @@ public bool IsCompilerDiagnostic(string language, DiagnosticData diagnostic) return builder.ToImmutable(); } - private ImmutableDictionary> CreateHostDiagnosticAnalyzers(string language) + private ImmutableDictionary> CreateHostDiagnosticAnalyzersAndBuildMap(string language) { Contract.ThrowIfNull(language); + var nameMap = CreateAnalyzerPathToPackageNameMap(); + var builder = ImmutableDictionary.CreateBuilder>(); foreach (var kv in _hostAnalyzerReferencesMap) { @@ -213,6 +279,8 @@ public bool IsCompilerDiagnostic(string language, DiagnosticData diagnostic) UpdateCompilerAnalyzerMapIfNeeded(language, analyzers); + UpdateDiagnosticAnalyzerToPackageNameMap(nameMap, reference, analyzers); + // there can't be duplication since _hostAnalyzerReferenceMap is already de-duplicated. builder.Add(referenceIdenity, analyzers); } @@ -220,6 +288,46 @@ public bool IsCompilerDiagnostic(string language, DiagnosticData diagnostic) return builder.ToImmutable(); } + private void UpdateDiagnosticAnalyzerToPackageNameMap( + ImmutableDictionary nameMap, + AnalyzerReference reference, + ImmutableArray analyzers) + { + var fileReference = reference as AnalyzerFileReference; + if (fileReference == null) + { + return; + } + + string name; + if (!nameMap.TryGetValue(fileReference.FullPath, out name)) + { + return; + } + + foreach (var analyzer in analyzers) + { + ImmutableInterlocked.GetOrAdd(ref _hostDiagnosticAnalzyerPackageNameMap, analyzer, _ => name); + } + } + + private ImmutableDictionary CreateAnalyzerPathToPackageNameMap() + { + var builder = ImmutableDictionary.CreateBuilder(StringComparer.OrdinalIgnoreCase); + foreach (var package in _hostDiagnosticAnalyzerPackages) + { + foreach (var assembly in package.Assemblies) + { + if (!builder.ContainsKey(assembly)) + { + builder.Add(assembly, package.Name); + } + } + } + + return builder.ToImmutable(); + } + private void UpdateCompilerAnalyzerMapIfNeeded(string language, ImmutableArray analyzers) { if (_compilerDiagnosticAnalyzerMap.ContainsKey(language)) @@ -292,13 +400,15 @@ private bool CheckAnalyzerReferenceIdentity(AnalyzerReference reference) return builder.ToImmutable(); } - private static ImmutableArray CreateAnalyzerReferencesFromAssemblies(IEnumerable analyzerAssemblies) + private static ImmutableArray CreateAnalyzerReferencesFromPackages(IEnumerable analyzerPackages) { - if (analyzerAssemblies == null || analyzerAssemblies.IsEmpty()) + if (analyzerPackages == null || analyzerPackages.IsEmpty()) { return ImmutableArray.Empty; } + var analyzerAssemblies = analyzerPackages.SelectMany(p => p.Assemblies); + // We want to load the analyzer assembly assets in default context. // Use Assembly.Load instead of Assembly.LoadFrom to ensure that if the assembly is ngen'ed, then the native image gets loaded. Func getAssembly = (fullPath) => Assembly.Load(AssemblyName.GetAssemblyName(fullPath)); diff --git a/src/Features/Core/Diagnostics/HostDiagnosticAnalyzerPackage.cs b/src/Features/Core/Diagnostics/HostDiagnosticAnalyzerPackage.cs new file mode 100644 index 00000000000..5acf38803c2 --- /dev/null +++ b/src/Features/Core/Diagnostics/HostDiagnosticAnalyzerPackage.cs @@ -0,0 +1,21 @@ +// 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 System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + /// + /// Information on vsix that contains diagnostic analyzers + /// + internal class HostDiagnosticAnalyzerPackage + { + public readonly string Name; + public readonly ImmutableArray Assemblies; + + public HostDiagnosticAnalyzerPackage(string name, ImmutableArray assemblies) + { + this.Name = name; + this.Assemblies = assemblies; + } + } +} diff --git a/src/Features/Core/Diagnostics/IDiagnosticAnalyzerService.cs b/src/Features/Core/Diagnostics/IDiagnosticAnalyzerService.cs index 0fdaa06644d..5cca53ef229 100644 --- a/src/Features/Core/Diagnostics/IDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Diagnostics/IDiagnosticAnalyzerService.cs @@ -81,5 +81,15 @@ internal interface IDiagnosticAnalyzerService /// Check whether given diagnostic is compiler diagnostic or not /// bool IsCompilerDiagnostic(string language, DiagnosticData diagnostic); + + /// + /// Get compiler analyzer for the given language + /// + DiagnosticAnalyzer GetCompilerDiagnosticAnalyzer(string language); + + /// + /// Check whether given is compiler analyzer for the language or not. + /// + bool IsCompilerDiagnosticAnalyzer(string language, DiagnosticAnalyzer analyzer); } } diff --git a/src/Features/Core/Diagnostics/ISupportLiveUpdate.cs b/src/Features/Core/Diagnostics/ISupportLiveUpdate.cs new file mode 100644 index 00000000000..54fc4a20923 --- /dev/null +++ b/src/Features/Core/Diagnostics/ISupportLiveUpdate.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + /// + /// Marker interface to indicate whether given diagnostic args are from live analysis. + /// + internal interface ISupportLiveUpdate + { + } +} diff --git a/src/Features/Core/Diagnostics/IWorkspaceDiagnosticAnalyzerProviderService.cs b/src/Features/Core/Diagnostics/IWorkspaceDiagnosticAnalyzerProviderService.cs index c3e2b533861..7d1119b794e 100644 --- a/src/Features/Core/Diagnostics/IWorkspaceDiagnosticAnalyzerProviderService.cs +++ b/src/Features/Core/Diagnostics/IWorkspaceDiagnosticAnalyzerProviderService.cs @@ -1,8 +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 System; using System.Collections.Generic; -using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.Diagnostics { @@ -12,7 +10,6 @@ internal interface IWorkspaceDiagnosticAnalyzerProviderService /// Gets the analyzers shared across the entire workspace session. /// This includes the analyzers included through VSIX installations. /// - /// - IEnumerable GetWorkspaceAnalyzerAssemblies(); + IEnumerable GetHostDiagnosticAnalyzerPackages(); } } diff --git a/src/Features/Core/Diagnostics/PredefinedErrorSources.cs b/src/Features/Core/Diagnostics/PredefinedErrorSources.cs new file mode 100644 index 00000000000..30183db4533 --- /dev/null +++ b/src/Features/Core/Diagnostics/PredefinedErrorSources.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.Diagnostics +{ + internal static class PredefinedErrorSources + { + public static readonly string Build = FeaturesResources.ErrorSourceBuild; + public static readonly string EnC = FeaturesResources.ErrorSourceEnC; + public static readonly string Compiler = FeaturesResources.ErrorSourceIntelliSense; + } +} diff --git a/src/Features/Core/Diagnostics/UpdateArgsId.cs b/src/Features/Core/Diagnostics/UpdateArgsId.cs deleted file mode 100644 index 87ed08178aa..00000000000 --- a/src/Features/Core/Diagnostics/UpdateArgsId.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.CodeAnalysis.Diagnostics -{ - /// - /// Base type of a type that is used as for live diagnostic - /// - internal class UpdateArgsId - { - public readonly DiagnosticAnalyzer Analyzer; - - protected UpdateArgsId(DiagnosticAnalyzer analyzer) - { - Analyzer = analyzer; - } - - public override bool Equals(object obj) - { - var other = obj as UpdateArgsId; - if (other == null) - { - return false; - } - - return Analyzer == other.Analyzer; - } - - public override int GetHashCode() - { - return Analyzer == null ? 0 : Analyzer.GetHashCode(); - } - } -} diff --git a/src/Features/Core/Features.csproj b/src/Features/Core/Features.csproj index 0890dba1e11..ac04d8b2db9 100644 --- a/src/Features/Core/Features.csproj +++ b/src/Features/Core/Features.csproj @@ -180,6 +180,9 @@ + + + @@ -188,6 +191,7 @@ + @@ -217,7 +221,7 @@ - + diff --git a/src/Features/Core/FeaturesResources.Designer.cs b/src/Features/Core/FeaturesResources.Designer.cs index 7f2182e57c2..fa830a651d5 100644 --- a/src/Features/Core/FeaturesResources.Designer.cs +++ b/src/Features/Core/FeaturesResources.Designer.cs @@ -591,6 +591,33 @@ internal class FeaturesResources { } } + /// + /// Looks up a localized string similar to Build. + /// + internal static string ErrorSourceBuild { + get { + return ResourceManager.GetString("ErrorSourceBuild", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Edit And Continue. + /// + internal static string ErrorSourceEnC { + get { + return ResourceManager.GetString("ErrorSourceEnC", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IntelliSense Build. + /// + internal static string ErrorSourceIntelliSense { + get { + return ResourceManager.GetString("ErrorSourceIntelliSense", resourceCulture); + } + } + /// /// Looks up a localized string similar to Exceptions:. /// diff --git a/src/Features/Core/FeaturesResources.resx b/src/Features/Core/FeaturesResources.resx index f2bf086708b..37e25c33dfc 100644 --- a/src/Features/Core/FeaturesResources.resx +++ b/src/Features/Core/FeaturesResources.resx @@ -762,4 +762,13 @@ Do you want to continue? Modifying '{0}' which contains a static variable will prevent the debug session from continuing. + + Build + + + Edit And Continue + + + IntelliSense Build + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/MiscellaneousDiagnosticAnalyzerService.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/MiscellaneousDiagnosticAnalyzerService.cs index 16f3c404c54..836ccec083a 100644 --- a/src/VisualStudio/Core/Def/Implementation/Diagnostics/MiscellaneousDiagnosticAnalyzerService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/MiscellaneousDiagnosticAnalyzerService.cs @@ -21,6 +21,14 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics [Shared] internal partial class MiscellaneousDiagnosticAnalyzerService : IIncrementalAnalyzerProvider, IDiagnosticUpdateSource { + private readonly IDiagnosticAnalyzerService analyzerService; + + [ImportingConstructor] + public MiscellaneousDiagnosticAnalyzerService(IDiagnosticAnalyzerService analyzerService) + { + this.analyzerService = analyzerService; + } + public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) { if (!workspace.Options.GetOption(ServiceComponentOnOffOptions.DiagnosticProvider)) @@ -82,7 +90,9 @@ public async Task AnalyzeSyntaxAsync(Document document, CancellationToken cancel Contract.Requires(document.Project.Solution.Workspace == _workspace); var diagnosticData = diagnostics == null ? ImmutableArray.Empty : diagnostics.Select(d => DiagnosticData.Create(document, d)).ToImmutableArrayOrEmpty(); - _service.RaiseDiagnosticsUpdated(new DiagnosticsUpdatedArgs(new MiscUpdateArgsId(document.Id), _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); + _service.RaiseDiagnosticsUpdated( + new DiagnosticsUpdatedArgs(new MiscUpdateArgsId(document.Id), + _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData)); } public void RemoveDocument(DocumentId documentId) @@ -137,13 +147,18 @@ public void RemoveProject(ProjectId projectId) { } - private class MiscUpdateArgsId : UpdateArgsId + private class MiscUpdateArgsId : ErrorSourceId.Base, ISupportLiveUpdate { - private readonly DocumentId _documentId; + public MiscUpdateArgsId(DocumentId documentId) : base(documentId) + { + } - public MiscUpdateArgsId(DocumentId documentId) : base(null) + public override string ErrorSource { - _documentId = documentId; + get + { + return PredefinedErrorSources.Compiler; + } } public override bool Equals(object obj) @@ -154,12 +169,12 @@ public override bool Equals(object obj) return false; } - return _documentId == other._documentId && base.Equals(obj); + return base.Equals(obj); } public override int GetHashCode() { - return Hash.Combine(_documentId.GetHashCode(), base.GetHashCode()); + return base.GetHashCode(); } } } diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs index 685f5bd2bba..a01d8a506c5 100644 --- a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioWorkspaceDiagnosticAnalyzerProviderService.cs @@ -1,7 +1,11 @@ // 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 System; using System.Collections.Generic; +using System.Collections.Immutable; using System.ComponentModel.Composition; +using System.IO; +using System.Linq; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.VisualStudio.ExtensionManager; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -13,22 +17,38 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics /// These analyzers are used across this workspace session. /// [Export(typeof(IWorkspaceDiagnosticAnalyzerProviderService))] - internal partial class VisualStudioWorkspaceDiagnosticAnalyzerProviderService : IWorkspaceDiagnosticAnalyzerProviderService + internal class VisualStudioWorkspaceDiagnosticAnalyzerProviderService : IWorkspaceDiagnosticAnalyzerProviderService { - private readonly IEnumerable _workspaceAnalyzerAssemblies; private const string AnalyzerContentTypeName = "Microsoft.VisualStudio.Analyzer"; + private readonly ImmutableArray _hostDiagnosticAnalyzerInfo; + [ImportingConstructor] public VisualStudioWorkspaceDiagnosticAnalyzerProviderService(VisualStudioWorkspaceImpl workspace) { // Get the analyzer assets for installed VSIX extensions through the VSIX extension manager. var extensionManager = workspace.GetVsService(); - _workspaceAnalyzerAssemblies = extensionManager.GetEnabledExtensionContentLocations(AnalyzerContentTypeName); + + var builder = ImmutableArray.CreateBuilder(); + foreach (var extension in extensionManager.GetEnabledExtensions(AnalyzerContentTypeName)) + { + var name = extension.Header.LocalizedName; + var assemblies = extension.Content.Where(ShouldInclude).Select(c => Path.Combine(extension.InstallPath, c.RelativePath)); + + builder.Add(new HostDiagnosticAnalyzerPackage(name, assemblies.ToImmutableArray())); + } + + _hostDiagnosticAnalyzerInfo = builder.ToImmutable(); + } + + public IEnumerable GetHostDiagnosticAnalyzerPackages() + { + return _hostDiagnosticAnalyzerInfo; } - public IEnumerable GetWorkspaceAnalyzerAssemblies() + private bool ShouldInclude(IExtensionContent content) { - return _workspaceAnalyzerAssemblies; + return string.Equals(content.ContentTypeName, AnalyzerContentTypeName, StringComparison.InvariantCultureIgnoreCase); } } } diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs index a865e9ca074..43ab061364c 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs @@ -30,6 +30,7 @@ internal class VisualStudioBaseDiagnosticListTable : AbstractTable private readonly ProjectId _projectId; private readonly DocumentId _documentId; private readonly object _id; + private readonly string _errorSource; - public TableEntriesFactory(TableDataSource source, Workspace workspace, ProjectId projectId, DocumentId documentId, object id) : + public TableEntriesFactory(TableDataSource source, Workspace workspace, ProjectId projectId, DocumentId documentId, object id) : base(source) { _source = source; @@ -190,6 +192,7 @@ private class TableEntriesFactory : AbstractTableEntriesFactory _projectId = projectId; _documentId = documentId; _id = id; + _errorSource = (id as ErrorSourceId)?.ErrorSource ?? string.Empty; } protected override ImmutableArray GetItems() @@ -287,6 +290,9 @@ public override bool TryGetValue(int index, string columnName, out object conten case StandardTableKeyNames.ErrorCategory: content = item.Category; return true; + case StandardTableKeyNames.ErrorSource: + content = _factory._errorSource; + return content != null; case StandardTableKeyNames.Text: content = item.Message; return true; diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs index fecc999ceb2..89db6b7f247 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs @@ -454,23 +454,15 @@ private HashSet GetErrors(Dictionary { - public object Key; - - public ArgumentKey(object key) - { - this.Key = key; - } - - public DocumentId DocumentId + public ArgumentKey(object key) : base(key) { - get { return this.Key as DocumentId; } } - public ProjectId ProjectId + public override string ErrorSource { - get { return this.Key as ProjectId; } + get { return PredefinedErrorSources.Build; } } public override bool Equals(object obj) @@ -481,12 +473,12 @@ public override bool Equals(object obj) return false; } - return Key == other.Key; + return base.Equals(obj); } public override int GetHashCode() { - return this.Key.GetHashCode(); + return base.GetHashCode(); } } diff --git a/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb index f442bb0f6f6..5f46024bccb 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb @@ -489,6 +489,35 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Using End Sub + + Public Sub TestErrorSource() + Using workspace = CSharpWorkspaceFactory.CreateWorkspaceFromLines(String.Empty) + Dim documentId = workspace.CurrentSolution.Projects.First().DocumentIds.First() + Dim projectId = documentId.ProjectId + + Dim item1 = CreateItem(workspace, projectId, documentId, DiagnosticSeverity.Error, "http://link/") + Dim provider = New TestDiagnosticService(item1) + + Dim tableManagerProvider = New TestTableManagerProvider() + + Dim table = New VisualStudioDiagnosticListTable(workspace, provider, tableManagerProvider) + provider.RaiseDiagnosticsUpdated(workspace) + + Dim manager = DirectCast(table.TableManager, TestTableManagerProvider.TestTableManager) + Dim source = DirectCast(manager.Sources.First(), AbstractRoslynTableDataSource(Of DiagnosticsUpdatedArgs, DiagnosticData)) + Dim sinkAndSubscription = manager.Sinks_TestOnly.First() + + Dim sink = DirectCast(sinkAndSubscription.Key, TestTableManagerProvider.TestTableManager.TestSink) + Dim snapshot = sink.Entries.First().GetCurrentSnapshot() + Assert.Equal(1, snapshot.Count) + + Dim errorSource As Object = Nothing + Assert.True(snapshot.TryGetValue(0, StandardTableKeyNames.ErrorSource, errorSource)) + + Assert.Equal("ErrorSource", errorSource.ToString()) + End Using + End Sub + Private Function CreateItem(workspace As Workspace, documentId As DocumentId, Optional severity As DiagnosticSeverity = DiagnosticSeverity.Error) As DiagnosticData Return CreateItem(workspace, documentId.ProjectId, documentId, severity) End Function @@ -529,7 +558,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim id = If(CObj(item.DocumentId), item.ProjectId) RaiseEvent DiagnosticsUpdated(Me, New DiagnosticsUpdatedArgs( - ValueTuple.Create(Of IDiagnosticService, Object)(Me, id), workspace, workspace.CurrentSolution, item.ProjectId, item.DocumentId, items.ToImmutableArray())) + New ErrorId(Me, id), workspace, workspace.CurrentSolution, item.ProjectId, item.DocumentId, items.ToImmutableArray())) End Sub Public Sub RaiseDiagnosticsUpdated(workspace As Workspace) @@ -537,21 +566,35 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics For Each group In documentMap RaiseEvent DiagnosticsUpdated(Me, New DiagnosticsUpdatedArgs( - ValueTuple.Create(Of IDiagnosticService, Object)(Me, group.Key), workspace, workspace.CurrentSolution, group.Key.ProjectId, group.Key, group.ToImmutableArrayOrEmpty())) + New ErrorId(Me, group.Key), workspace, workspace.CurrentSolution, group.Key.ProjectId, group.Key, group.ToImmutableArrayOrEmpty())) Next Dim projectMap = Items.Where(Function(t) t.DocumentId Is Nothing).Where(Function(t) t.Workspace Is workspace).ToLookup(Function(t) t.ProjectId) For Each group In projectMap RaiseEvent DiagnosticsUpdated(Me, New DiagnosticsUpdatedArgs( - ValueTuple.Create(Of IDiagnosticService, Object)(Me, group.Key), workspace, workspace.CurrentSolution, group.Key, Nothing, group.ToImmutableArrayOrEmpty())) + New ErrorId(Me, group.Key), workspace, workspace.CurrentSolution, group.Key, Nothing, group.ToImmutableArrayOrEmpty())) Next End Sub Public Sub RaiseClearDiagnosticsUpdated(workspace As Workspace, projectId As ProjectId, documentId As DocumentId) RaiseEvent DiagnosticsUpdated(Me, New DiagnosticsUpdatedArgs( - ValueTuple.Create(Of IDiagnosticService, Object)(Me, documentId), workspace, workspace.CurrentSolution, projectId, documentId, ImmutableArray(Of DiagnosticData).Empty)) + New ErrorId(Me, documentId), workspace, workspace.CurrentSolution, projectId, documentId, ImmutableArray(Of DiagnosticData).Empty)) End Sub + + Private Class ErrorId + Inherits ErrorSourceId.Base(Of TestDiagnosticService, Object) + + Public Sub New(service As TestDiagnosticService, id As Object) + MyBase.New(service, id) + End Sub + + Public Overrides ReadOnly Property ErrorSource As String + Get + Return "ErrorSource" + End Get + End Property + End Class End Class End Class End Namespace \ No newline at end of file diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 1e5e3ac6203..d3a33cab707 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -173,6 +173,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Function IsCompilerDiagnostic(language As String, diagnostic As DiagnosticData) As Boolean Implements IDiagnosticAnalyzerService.IsCompilerDiagnostic Return False End Function + + Public Function GetCompilerDiagnosticAnalyzer(language As String) As DiagnosticAnalyzer Implements IDiagnosticAnalyzerService.GetCompilerDiagnosticAnalyzer + Return Nothing + End Function + + Public Function IsCompilerDiagnosticAnalyzer(language As String, analyzer As DiagnosticAnalyzer) As Boolean Implements IDiagnosticAnalyzerService.IsCompilerDiagnosticAnalyzer + Return False + End Function End Class End Class End Namespace diff --git a/src/VisualStudio/Core/Test/Diagnostics/MiscDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/MiscDiagnosticUpdateSourceTests.vb index 6e55ee6a786..9f25ee860c0 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/MiscDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/MiscDiagnosticUpdateSourceTests.vb @@ -22,7 +22,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics class 123 { } Using workspace = CSharpWorkspaceFactory.CreateWorkspaceFromLines(code.ToString()) - Dim miscService = New MiscellaneousDiagnosticAnalyzerService() + Dim miscService = New MiscellaneousDiagnosticAnalyzerService(New TestDiagnosticAnalyzerService(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap())) Assert.False(miscService.SupportGetDiagnostics) Dim diagnosticWaiter = New DiagnosticServiceWaiter() @@ -57,6 +57,49 @@ class 123 { } End Using End Sub + + Public Sub TestMiscCSharpErrorSource() + Dim code = +class 123 { } + + Using workspace = CSharpWorkspaceFactory.CreateWorkspaceFromLines(code.ToString()) + Dim miscService = New MiscellaneousDiagnosticAnalyzerService(New TestDiagnosticAnalyzerService(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap())) + Dim errorSource = String.Empty + + AddHandler miscService.DiagnosticsUpdated, Sub(e, a) + Dim id = DirectCast(a.Id, ErrorSourceId) + errorSource = id.ErrorSource + End Sub + + Dim analyzer = miscService.CreateIncrementalAnalyzer(workspace) + analyzer.AnalyzeSyntaxAsync(workspace.CurrentSolution.Projects.First().Documents.First(), CancellationToken.None).PumpingWait() + + Assert.Equal(PredefinedErrorSources.Compiler, errorSource) + End Using + End Sub + + + Public Sub TestMiscVBErrorSource() + Dim code = +Class 123 +End Class + + Using workspace = VisualBasicWorkspaceFactory.CreateWorkspaceFromLines(code.ToString()) + Dim miscService = New MiscellaneousDiagnosticAnalyzerService(New TestDiagnosticAnalyzerService(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap())) + Dim errorSource = String.Empty + + AddHandler miscService.DiagnosticsUpdated, Sub(e, a) + Dim id = DirectCast(a.Id, ErrorSourceId) + errorSource = id.ErrorSource + End Sub + + Dim analyzer = miscService.CreateIncrementalAnalyzer(workspace) + analyzer.AnalyzeSyntaxAsync(workspace.CurrentSolution.Projects.First().Documents.First(), CancellationToken.None).PumpingWait() + + Assert.Equal(PredefinedErrorSources.Compiler, errorSource) + End Using + End Sub + Private Class DiagnosticServiceWaiter : Inherits AsynchronousOperationListener : End Class Private Class ErrorSquiggleWaiter : Inherits AsynchronousOperationListener : End Class End Class diff --git a/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb b/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb index 2ccd2ab283f..33be7906b2e 100644 --- a/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb +++ b/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb @@ -94,8 +94,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.EditAndContinue Public Function IsCompilerDiagnostic(language As String, diagnostic As DiagnosticData) As Boolean Implements IDiagnosticAnalyzerService.IsCompilerDiagnostic Return False End Function - End Class - End Class + Public Function GetCompilerDiagnosticAnalyzer(language As String) As DiagnosticAnalyzer Implements IDiagnosticAnalyzerService.GetCompilerDiagnosticAnalyzer + Return Nothing + End Function + Public Function IsCompilerDiagnosticAnalyzer(language As String, analyzer As DiagnosticAnalyzer) As Boolean Implements IDiagnosticAnalyzerService.IsCompilerDiagnosticAnalyzer + Return False + End Function + End Class + End Class End Namespace \ No newline at end of file -- GitLab