未验证 提交 d1532d6e 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #44817 from CyrusNajmabadi/unnecessaryParenFading

Fix fading locations for unnecessary code.
...@@ -121,8 +121,10 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) ...@@ -121,8 +121,10 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
var severity = preference.Notification.Severity; var severity = preference.Notification.Severity;
var additionalLocations = ImmutableArray.Create(parenthesizedExpression.GetLocation(), var additionalLocations = ImmutableArray.Create(
parenthesizedExpression.GetFirstToken().GetLocation(), parenthesizedExpression.GetLastToken().GetLocation()); parenthesizedExpression.GetLocation(),
parenthesizedExpression.GetFirstToken().GetLocation(),
parenthesizedExpression.GetLastToken().GetLocation());
context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
s_diagnosticDescriptor, s_diagnosticDescriptor,
......
...@@ -230,7 +230,7 @@ public async Task SemanticErrorReported() ...@@ -230,7 +230,7 @@ public async Task SemanticErrorReported()
public async Task TestNoErrorsAfterDocumentRemoved() public async Task TestNoErrorsAfterDocumentRemoved()
{ {
using var workspace = TestWorkspace.CreateCSharp("class"); using var workspace = TestWorkspace.CreateCSharp("class");
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider>(workspace); using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider, IErrorTag>(workspace);
var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer()); var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
using var disposable = tagger as IDisposable; using var disposable = tagger as IDisposable;
await wrapper.WaitForTags(); await wrapper.WaitForTags();
...@@ -256,7 +256,7 @@ public async Task TestNoErrorsAfterDocumentRemoved() ...@@ -256,7 +256,7 @@ public async Task TestNoErrorsAfterDocumentRemoved()
public async Task TestNoErrorsAfterProjectRemoved() public async Task TestNoErrorsAfterProjectRemoved()
{ {
using var workspace = TestWorkspace.CreateCSharp("class"); using var workspace = TestWorkspace.CreateCSharp("class");
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider>(workspace); using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider, IErrorTag>(workspace);
var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer()); var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
using var disposable = tagger as IDisposable; using var disposable = tagger as IDisposable;
await wrapper.WaitForTags(); await wrapper.WaitForTags();
......
...@@ -60,13 +60,14 @@ internal partial class DiagnosticsClassificationTaggerProvider : AbstractDiagnos ...@@ -60,13 +60,14 @@ internal partial class DiagnosticsClassificationTaggerProvider : AbstractDiagnos
// If we are under high contrast mode, the editor ignores classification tags that fade things out, // If we are under high contrast mode, the editor ignores classification tags that fade things out,
// because that reduces contrast. Since the editor will ignore them, there's no reason to produce them. // because that reduces contrast. Since the editor will ignore them, there's no reason to produce them.
protected internal override bool IsEnabled => !_editorOptionsFactoryService.GlobalOptions.GetOptionValue(DefaultTextViewHostOptions.IsInContrastModeId); protected internal override bool IsEnabled
=> !_editorOptionsFactoryService.GlobalOptions.GetOptionValue(DefaultTextViewHostOptions.IsInContrastModeId);
protected internal override bool IncludeDiagnostic(DiagnosticData data) => protected internal override bool IncludeDiagnostic(DiagnosticData data)
data.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary); => data.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary);
protected internal override ITagSpan<ClassificationTag> CreateTagSpan(Workspace workspace, bool isLiveUpdate, SnapshotSpan span, DiagnosticData data) => protected internal override ITagSpan<ClassificationTag> CreateTagSpan(Workspace workspace, bool isLiveUpdate, SnapshotSpan span, DiagnosticData data)
new TagSpan<ClassificationTag>(span, _classificationTag); => new TagSpan<ClassificationTag>(span, _classificationTag);
protected internal override ImmutableArray<DiagnosticDataLocation> GetLocationsToTag(DiagnosticData diagnosticData) protected internal override ImmutableArray<DiagnosticDataLocation> GetLocationsToTag(DiagnosticData diagnosticData)
{ {
...@@ -76,24 +77,26 @@ protected internal override ImmutableArray<DiagnosticDataLocation> GetLocationsT ...@@ -76,24 +77,26 @@ protected internal override ImmutableArray<DiagnosticDataLocation> GetLocationsT
&& diagnosticData.Properties.TryGetValue(WellKnownDiagnosticTags.Unnecessary, out var unnecessaryIndices) && diagnosticData.Properties.TryGetValue(WellKnownDiagnosticTags.Unnecessary, out var unnecessaryIndices)
&& unnecessaryIndices is object) && unnecessaryIndices is object)
{ {
using var locationsToTagDisposer = PooledObjects.ArrayBuilder<DiagnosticDataLocation>.GetInstance(out var locationsToTag); using var _ = PooledObjects.ArrayBuilder<DiagnosticDataLocation>.GetInstance(out var locationsToTag);
var additionalLocations = diagnosticData.AdditionalLocations.ToImmutableArray(); var additionalLocations = diagnosticData.AdditionalLocations.ToImmutableArray();
var indices = GetLocationIndices(unnecessaryIndices); foreach (var index in GetLocationIndices(unnecessaryIndices))
locationsToTag.AddRange(indices.Select(i => additionalLocations[i]).ToImmutableArray()); locationsToTag.Add(additionalLocations[index]);
return locationsToTag.ToImmutable();
} }
// Default to the base implementation for the diagnostic data // Default to the base implementation for the diagnostic data
return base.GetLocationsToTag(diagnosticData); return base.GetLocationsToTag(diagnosticData);
static IEnumerable<int>? GetLocationIndices(string indicesProperty) static IEnumerable<int> GetLocationIndices(string indicesProperty)
{ {
try try
{ {
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(indicesProperty)); using var stream = new MemoryStream(Encoding.UTF8.GetBytes(indicesProperty));
var serializer = new DataContractJsonSerializer(typeof(IEnumerable<int>)); var serializer = new DataContractJsonSerializer(typeof(IEnumerable<int>));
var result = serializer.ReadObject(stream) as IEnumerable<int>; var result = serializer.ReadObject(stream) as IEnumerable<int>;
return result; return result ?? Array.Empty<int>();
} }
catch (Exception e) when (FatalError.ReportWithoutCrash(e)) catch (Exception e) when (FatalError.ReportWithoutCrash(e))
{ {
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Tagging;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
{
[UseExportProvider]
public class DiagnosticsClassificationTaggerProviderTests
{
[WpfFact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public async Task Test_FadingSpans()
{
var analyzer = new Analyzer();
var analyzerMap = new Dictionary<string, ImmutableArray<DiagnosticAnalyzer>>
{
{ LanguageNames.CSharp, ImmutableArray.Create<DiagnosticAnalyzer>(analyzer) }
};
using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }", "class E { }" }, CSharpParseOptions.Default);
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsClassificationTaggerProvider, ClassificationTag>(workspace, analyzerMap);
var tagger = wrapper.TaggerProvider.CreateTagger<ClassificationTag>(workspace.Documents.First().GetTextBuffer());
using var disposable = tagger as IDisposable;
// test first update
await wrapper.WaitForTags();
// We should get two spans, the 1-index and 2-index locations in the original diagnostic.
var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot;
var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToList();
Assert.Equal(2, spans.Count);
Assert.Equal(new Span(0, 1), spans[0].Span.Span);
Assert.Equal(new Span(9, 1), spans[1].Span.Span);
Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[0].Tag.ClassificationType.Classification);
Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[1].Tag.ClassificationType.Classification);
}
private class Analyzer : DiagnosticAnalyzer
{
// Mark elements 1, and 2 in the locations as the fading locations.
private static readonly ImmutableDictionary<string, IEnumerable<int>> s_fadeLocations = new Dictionary<string, IEnumerable<int>>
{
{ nameof(WellKnownDiagnosticTags.Unnecessary), new int[] { 1, 2 } },
}.ToImmutableDictionary();
private readonly DiagnosticDescriptor _rule = new DiagnosticDescriptor(
"test", "test", "test", "test", DiagnosticSeverity.Error, true,
customTags: DiagnosticCustomTags.Create(isUnnecessary: true, isConfigurable: false));
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(_rule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxTreeAction(c =>
{
c.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags(
_rule, Location.Create(c.Tree, new TextSpan(0, 10)),
ReportDiagnostic.Error,
new Location[] {
Location.Create(c.Tree, new TextSpan(0, 10)),
Location.Create(c.Tree, new TextSpan(0, 1)),
Location.Create(c.Tree, new TextSpan(9, 1)),
},
s_fadeLocations));
});
}
}
}
}
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Common;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics; using Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics;
...@@ -42,7 +41,7 @@ public async Task Test_TagSourceDiffer() ...@@ -42,7 +41,7 @@ public async Task Test_TagSourceDiffer()
}; };
using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }", "class E { }" }, CSharpParseOptions.Default); using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }", "class E { }" }, CSharpParseOptions.Default);
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider>(workspace, analyzerMap); using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider, IErrorTag>(workspace, analyzerMap);
var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer()); var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
using var disposable = tagger as IDisposable; using var disposable = tagger as IDisposable;
// test first update // test first update
...@@ -70,7 +69,7 @@ public async Task Test_TagSourceDiffer() ...@@ -70,7 +69,7 @@ public async Task Test_TagSourceDiffer()
public async Task MultipleTaggersAndDispose() public async Task MultipleTaggersAndDispose()
{ {
using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A {" }, CSharpParseOptions.Default); using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A {" }, CSharpParseOptions.Default);
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider>(workspace); using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider, IErrorTag>(workspace);
// Make two taggers. // Make two taggers.
var tagger1 = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer()); var tagger1 = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
var tagger2 = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer()); var tagger2 = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
...@@ -90,7 +89,7 @@ public async Task MultipleTaggersAndDispose() ...@@ -90,7 +89,7 @@ public async Task MultipleTaggersAndDispose()
public async Task TaggerProviderCreatedAfterInitialDiagnosticsReported() public async Task TaggerProviderCreatedAfterInitialDiagnosticsReported()
{ {
using var workspace = TestWorkspace.CreateCSharp(new string[] { "class C {" }, CSharpParseOptions.Default); using var workspace = TestWorkspace.CreateCSharp(new string[] { "class C {" }, CSharpParseOptions.Default);
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider>(workspace, analyzerMap: null, createTaggerProvider: false); using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider, IErrorTag>(workspace, analyzerMap: null, createTaggerProvider: false);
// First, make sure all diagnostics have been reported. // First, make sure all diagnostics have been reported.
await wrapper.WaitForTags(); await wrapper.WaitForTags();
...@@ -118,7 +117,7 @@ public async Task TestWithMockDiagnosticService_TaggerProviderCreatedBeforeIniti ...@@ -118,7 +117,7 @@ public async Task TestWithMockDiagnosticService_TaggerProviderCreatedBeforeIniti
// diagnostics engine not actually reporting all diagnostics properly. // diagnostics engine not actually reporting all diagnostics properly.
using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }" }, CSharpParseOptions.Default); using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }" }, CSharpParseOptions.Default);
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider>(workspace); using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider, IErrorTag>(workspace);
var listenerProvider = workspace.ExportProvider.GetExportedValue<IAsynchronousOperationListenerProvider>(); var listenerProvider = workspace.ExportProvider.GetExportedValue<IAsynchronousOperationListenerProvider>();
var diagnosticService = new MockDiagnosticService(workspace); var diagnosticService = new MockDiagnosticService(workspace);
...@@ -156,7 +155,7 @@ public async Task TestWithMockDiagnosticService_TaggerProviderCreatedAfterInitia ...@@ -156,7 +155,7 @@ public async Task TestWithMockDiagnosticService_TaggerProviderCreatedAfterInitia
// diagnostics engine not actually reporting all diagnostics properly. // diagnostics engine not actually reporting all diagnostics properly.
using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }" }, CSharpParseOptions.Default); using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }" }, CSharpParseOptions.Default);
using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider>(workspace); using var wrapper = new DiagnosticTaggerWrapper<DiagnosticsSquiggleTaggerProvider, IErrorTag>(workspace);
var listenerProvider = workspace.ExportProvider.GetExportedValue<IAsynchronousOperationListenerProvider>(); var listenerProvider = workspace.ExportProvider.GetExportedValue<IAsynchronousOperationListenerProvider>();
var diagnosticService = new MockDiagnosticService(workspace); var diagnosticService = new MockDiagnosticService(workspace);
...@@ -182,70 +181,6 @@ public async Task TestWithMockDiagnosticService_TaggerProviderCreatedAfterInitia ...@@ -182,70 +181,6 @@ public async Task TestWithMockDiagnosticService_TaggerProviderCreatedAfterInitia
Assert.Equal(span.ToSpan(), spans[0].Span.Span); Assert.Equal(span.ToSpan(), spans[0].Span.Span);
} }
private class MockDiagnosticService : IDiagnosticService
{
public const string DiagnosticId = "MockId";
private readonly Workspace _workspace;
private DiagnosticData? _diagnostic;
public event EventHandler<DiagnosticsUpdatedArgs>? DiagnosticsUpdated;
public MockDiagnosticService(Workspace workspace)
=> _workspace = workspace;
public IEnumerable<DiagnosticData> GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken)
{
Assert.Equal(workspace, _workspace);
Assert.Equal(projectId, GetProjectId());
Assert.Equal(documentId, GetDocumentId());
if (_diagnostic == null)
{
yield break;
}
else
{
yield return _diagnostic;
}
}
public IEnumerable<UpdatedEventArgs> GetDiagnosticsUpdatedEventArgs(Workspace workspace, ProjectId projectId, DocumentId documentId, CancellationToken cancellationToken)
{
Assert.Equal(workspace, _workspace);
Assert.Equal(projectId, GetProjectId());
Assert.Equal(documentId, GetDocumentId());
if (_diagnostic == null)
{
yield break;
}
else
{
yield return new UpdatedEventArgs(this, workspace, GetProjectId(), GetDocumentId());
}
}
internal void CreateDiagnosticAndFireEvents(Location location)
{
var document = _workspace.CurrentSolution.Projects.Single().Documents.Single();
_diagnostic = DiagnosticData.Create(Diagnostic.Create(DiagnosticId, "MockCategory", "MockMessage", DiagnosticSeverity.Error, DiagnosticSeverity.Error, isEnabledByDefault: true, warningLevel: 0,
location: location),
document);
DiagnosticsUpdated?.Invoke(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
this, _workspace, _workspace.CurrentSolution,
GetProjectId(), GetDocumentId(),
ImmutableArray.Create(_diagnostic)));
}
private DocumentId GetDocumentId()
=> _workspace.CurrentSolution.Projects.Single().Documents.Single().Id;
private ProjectId GetProjectId()
=> _workspace.CurrentSolution.Projects.Single().Id;
}
private class Analyzer : DiagnosticAnalyzer private class Analyzer : DiagnosticAnalyzer
{ {
private DiagnosticDescriptor _rule = new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Error, true); private DiagnosticDescriptor _rule = new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Error, true);
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Common;
using Microsoft.CodeAnalysis.Diagnostics;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
{
internal class MockDiagnosticService : IDiagnosticService
{
public const string DiagnosticId = "MockId";
private readonly Workspace _workspace;
private DiagnosticData? _diagnostic;
public event EventHandler<DiagnosticsUpdatedArgs>? DiagnosticsUpdated;
public MockDiagnosticService(Workspace workspace)
=> _workspace = workspace;
public IEnumerable<DiagnosticData> GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken)
{
Assert.Equal(workspace, _workspace);
Assert.Equal(projectId, GetProjectId());
Assert.Equal(documentId, GetDocumentId());
if (_diagnostic == null)
{
yield break;
}
else
{
yield return _diagnostic;
}
}
public IEnumerable<UpdatedEventArgs> GetDiagnosticsUpdatedEventArgs(Workspace workspace, ProjectId projectId, DocumentId documentId, CancellationToken cancellationToken)
{
Assert.Equal(workspace, _workspace);
Assert.Equal(projectId, GetProjectId());
Assert.Equal(documentId, GetDocumentId());
if (_diagnostic == null)
{
yield break;
}
else
{
yield return new UpdatedEventArgs(this, workspace, GetProjectId(), GetDocumentId());
}
}
internal void CreateDiagnosticAndFireEvents(Location location)
{
var document = _workspace.CurrentSolution.Projects.Single().Documents.Single();
_diagnostic = DiagnosticData.Create(Diagnostic.Create(DiagnosticId, "MockCategory", "MockMessage", DiagnosticSeverity.Error, DiagnosticSeverity.Error, isEnabledByDefault: true, warningLevel: 0,
location: location),
document);
DiagnosticsUpdated?.Invoke(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
this, _workspace, _workspace.CurrentSolution,
GetProjectId(), GetDocumentId(),
ImmutableArray.Create(_diagnostic)));
}
private DocumentId GetDocumentId()
=> _workspace.CurrentSolution.Projects.Single().Documents.Single().Id;
private ProjectId GetProjectId()
=> _workspace.CurrentSolution.Projects.Single().Id;
}
}
...@@ -7,12 +7,12 @@ ...@@ -7,12 +7,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics; using Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Text.Tagging;
...@@ -20,8 +20,9 @@ ...@@ -20,8 +20,9 @@
namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
{ {
internal class DiagnosticTaggerWrapper<TProvider> : IDisposable internal class DiagnosticTaggerWrapper<TProvider, TTag> : IDisposable
where TProvider : AbstractDiagnosticsAdornmentTaggerProvider<IErrorTag> where TProvider : AbstractDiagnosticsTaggerProvider<TTag>
where TTag : ITag
{ {
private readonly TestWorkspace _workspace; private readonly TestWorkspace _workspace;
public readonly DiagnosticAnalyzerService? AnalyzerService; public readonly DiagnosticAnalyzerService? AnalyzerService;
...@@ -56,7 +57,7 @@ internal class DiagnosticTaggerWrapper<TProvider> : IDisposable ...@@ -56,7 +57,7 @@ internal class DiagnosticTaggerWrapper<TProvider> : IDisposable
_registrationService = workspace.Services.GetRequiredService<ISolutionCrawlerRegistrationService>(); _registrationService = workspace.Services.GetRequiredService<ISolutionCrawlerRegistrationService>();
_registrationService.Register(workspace); _registrationService.Register(workspace);
DiagnosticService = new DiagnosticService(_listenerProvider, Array.Empty<Lazy<IEventListener, EventListenerMetadata>>()); DiagnosticService = (DiagnosticService)workspace.ExportProvider.GetExportedValue<IDiagnosticService>();
DiagnosticService.Register(updateSource); DiagnosticService.Register(updateSource);
if (createTaggerProvider) if (createTaggerProvider)
...@@ -77,7 +78,7 @@ public ITaggerProvider TaggerProvider ...@@ -77,7 +78,7 @@ public ITaggerProvider TaggerProvider
{ {
if (_taggerProvider == null) if (_taggerProvider == null)
{ {
WpfTestRunner.RequireWpfFact($"{nameof(DiagnosticTaggerWrapper<TProvider>)}.{nameof(TaggerProvider)} creates asynchronous taggers"); WpfTestRunner.RequireWpfFact($"{nameof(DiagnosticTaggerWrapper<TProvider, TTag>)}.{nameof(TaggerProvider)} creates asynchronous taggers");
if (typeof(TProvider) == typeof(DiagnosticsSquiggleTaggerProvider)) if (typeof(TProvider) == typeof(DiagnosticsSquiggleTaggerProvider))
{ {
...@@ -95,6 +96,12 @@ public ITaggerProvider TaggerProvider ...@@ -95,6 +96,12 @@ public ITaggerProvider TaggerProvider
_workspace.GetService<IForegroundNotificationService>(), _workspace.GetService<IForegroundNotificationService>(),
_listenerProvider); _listenerProvider);
} }
else if (typeof(TProvider) == typeof(DiagnosticsClassificationTaggerProvider))
{
_taggerProvider = _workspace.ExportProvider.GetExportedValues<ITaggerProvider>()
.OfType<DiagnosticsClassificationTaggerProvider>()
.Single();
}
else else
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
...@@ -117,6 +124,7 @@ public async Task WaitForTags() ...@@ -117,6 +124,7 @@ public async Task WaitForTags()
await _listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync(); await _listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync();
await _listenerProvider.GetWaiter(FeatureAttribute.ErrorSquiggles).ExpeditedWaitAsync(); await _listenerProvider.GetWaiter(FeatureAttribute.ErrorSquiggles).ExpeditedWaitAsync();
await _listenerProvider.GetWaiter(FeatureAttribute.Classification).ExpeditedWaitAsync();
} }
private class MyDiagnosticAnalyzerService : DiagnosticAnalyzerService private class MyDiagnosticAnalyzerService : DiagnosticAnalyzerService
......
...@@ -26,21 +26,18 @@ public static class SquiggleUtilities ...@@ -26,21 +26,18 @@ public static class SquiggleUtilities
IReadOnlyDictionary<string, ImmutableArray<DiagnosticAnalyzer>> analyzerMap = null) IReadOnlyDictionary<string, ImmutableArray<DiagnosticAnalyzer>> analyzerMap = null)
where TProvider : AbstractDiagnosticsAdornmentTaggerProvider<IErrorTag> where TProvider : AbstractDiagnosticsAdornmentTaggerProvider<IErrorTag>
{ {
using (var wrapper = new DiagnosticTaggerWrapper<TProvider>(workspace, analyzerMap)) using var wrapper = new DiagnosticTaggerWrapper<TProvider, IErrorTag>(workspace, analyzerMap);
{ var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
using (var disposable = tagger as IDisposable)
{
await wrapper.WaitForTags();
var analyzerDiagnostics = await wrapper.AnalyzerService.GetDiagnosticsAsync(workspace.CurrentSolution); using var disposable = tagger as IDisposable;
await wrapper.WaitForTags();
var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; var analyzerDiagnostics = await wrapper.AnalyzerService.GetDiagnosticsAsync(workspace.CurrentSolution);
var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToImmutableArray();
return (analyzerDiagnostics, spans); var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot;
} var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToImmutableArray();
}
return (analyzerDiagnostics, spans);
} }
} }
...@@ -57,7 +54,7 @@ internal sealed class DiagnosticTagProducer<TProvider> ...@@ -57,7 +54,7 @@ internal sealed class DiagnosticTagProducer<TProvider>
internal async Task<IList<ITagSpan<IErrorTag>>> GetErrorsFromUpdateSource(TestWorkspace workspace, DiagnosticsUpdatedArgs updateArgs) internal async Task<IList<ITagSpan<IErrorTag>>> GetErrorsFromUpdateSource(TestWorkspace workspace, DiagnosticsUpdatedArgs updateArgs)
{ {
var source = new TestDiagnosticUpdateSource(); var source = new TestDiagnosticUpdateSource();
using (var wrapper = new DiagnosticTaggerWrapper<TProvider>(workspace, updateSource: source)) using (var wrapper = new DiagnosticTaggerWrapper<TProvider, IErrorTag>(workspace, updateSource: source))
{ {
var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer()); var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
using (var disposable = tagger as IDisposable) using (var disposable = tagger as IDisposable)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册