Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove code for arbitrary diagnostic taggers #72409

Merged
merged 10 commits into from
Mar 7, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,63 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.InlineDiagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions;
using Microsoft.CodeAnalysis.Editor.UnitTests.Squiggles;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Text.Adornments;
using Microsoft.VisualStudio.Text.Tagging;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.InlineDiagnostics
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.InlineDiagnostics;

[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.ErrorSquiggles), Trait(Traits.Feature, Traits.Features.Tagging)]
public class InlineDiagnosticsTaggerProviderTests
{
[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.ErrorSquiggles), Trait(Traits.Feature, Traits.Features.Tagging)]
public class InlineDiagnosticsTaggerProviderTests
[WpfFact]
public async Task ErrorTagGeneratedForError()
{
[WpfFact]
public async Task ErrorTagGeneratedForError()
{
var spans = await GetTagSpansAsync("class C {");
var firstSpan = Assert.Single(spans);
Assert.Equal(PredefinedErrorTypeNames.SyntaxError, firstSpan.Tag.ErrorType);
}
var spans = await GetTagSpansAsync("class C {");
var firstSpan = Assert.Single(spans);
Assert.Equal(PredefinedErrorTypeNames.SyntaxError, firstSpan.Tag.ErrorType);
}

[WpfFact]
public async Task ErrorTagGeneratedForErrorInSourceGeneratedDocument()
{
var spans = await GetTagSpansInSourceGeneratedDocumentAsync("class C {");
var firstSpan = Assert.Single(spans);
Assert.Equal(PredefinedErrorTypeNames.SyntaxError, firstSpan.Tag.ErrorType);
}
[WpfFact]
public async Task ErrorTagGeneratedForErrorInSourceGeneratedDocument()
{
var spans = await GetTagSpansInSourceGeneratedDocumentAsync("class C {");
var firstSpan = Assert.Single(spans);
Assert.Equal(PredefinedErrorTypeNames.SyntaxError, firstSpan.Tag.ErrorType);
}

private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(string content)
{
using var workspace = EditorTestWorkspace.CreateCSharp(content, composition: SquiggleUtilities.WpfCompositionWithSolutionCrawler);
Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(
workspace.CurrentSolution.Options.WithChangedOption(new OptionKey(DiagnosticOptionsStorage.PullDiagnosticsFeatureFlag), false))));
return await GetTagSpansAsync(workspace);
}
private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(string content)
{
using var workspace = EditorTestWorkspace.CreateCSharp(content, composition: SquiggleUtilities.WpfCompositionWithSolutionCrawler);
Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(
workspace.CurrentSolution.Options.WithChangedOption(new OptionKey(DiagnosticOptionsStorage.PullDiagnosticsFeatureFlag), false))));
return await GetTagSpansAsync(workspace);
}

private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansInSourceGeneratedDocumentAsync(string content)
{
using var workspace = EditorTestWorkspace.CreateCSharp(
files: [],
sourceGeneratedFiles: new[] { content },
composition: SquiggleUtilities.WpfCompositionWithSolutionCrawler);
Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(
workspace.CurrentSolution.Options.WithChangedOption(new OptionKey(DiagnosticOptionsStorage.PullDiagnosticsFeatureFlag), false))));
private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansInSourceGeneratedDocumentAsync(string content)
{
using var workspace = EditorTestWorkspace.CreateCSharp(
files: [],
sourceGeneratedFiles: new[] { content },
composition: SquiggleUtilities.WpfCompositionWithSolutionCrawler);
Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(
workspace.CurrentSolution.Options.WithChangedOption(new OptionKey(DiagnosticOptionsStorage.PullDiagnosticsFeatureFlag), false))));

return await GetTagSpansAsync(workspace);
}
return await GetTagSpansAsync(workspace);
}

private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(EditorTestWorkspace workspace)
{
workspace.GlobalOptions.SetGlobalOption(InlineDiagnosticsOptionsStorage.EnableInlineDiagnostics, LanguageNames.CSharp, true);
return (await TestDiagnosticTagProducer<InlineDiagnosticsTaggerProvider, InlineDiagnosticsTag>.GetDiagnosticsAndErrorSpans(workspace)).Item2;
}
private static async Task<ImmutableArray<ITagSpan<InlineDiagnosticsTag>>> GetTagSpansAsync(EditorTestWorkspace workspace)
{
workspace.GlobalOptions.SetGlobalOption(InlineDiagnosticsOptionsStorage.EnableInlineDiagnostics, LanguageNames.CSharp, true);
return (await TestDiagnosticTagProducer<InlineDiagnosticsTaggerProvider, InlineDiagnosticsTag>.GetDiagnosticsAndErrorSpans(workspace)).Item2;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ protected sealed override Task ProduceTagsAsync(
private async Task ProduceTagsAsync(
TaggerContext<TTag> context, DocumentSnapshotSpan documentSpanToTag, CancellationToken cancellationToken)
{
if (!_callback.IsEnabled)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no concept of 'enabled' or not. inline diagnostics aren't enabled/disabled depending on if we're using lsp diagnostics or not.

return;

var document = documentSpanToTag.Document;
if (document == null)
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Editor.Shared.Tagging;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
Expand Down Expand Up @@ -63,12 +64,11 @@ SingleDiagnosticKindPullTaggerProvider CreateDiagnosticsTaggerProvider(Diagnosti
protected abstract ImmutableArray<IOption2> Options { get; }
protected virtual ImmutableArray<IOption2> FeatureOptions { get; } = [];

protected abstract bool IsEnabled { get; }

protected abstract bool IncludeDiagnostic(DiagnosticData data);

protected abstract bool TagEquals(TTag tag1, TTag tag2);
protected abstract ITagSpan<TTag>? CreateTagSpan(Workspace workspace, SnapshotSpan span, DiagnosticData data);

protected abstract TTag? CreateTag(Workspace workspace, DiagnosticData diagnostic);

/// <summary>
/// Get the <see cref="DiagnosticDataLocation"/> that should have the tag applied to it.
Expand Down Expand Up @@ -111,4 +111,36 @@ private static ITaggerEventSource CreateEventSourceWorker(ITextBuffer subjectBuf
TaggerEventSources.OnDiagnosticsChanged(subjectBuffer, diagnosticService),
TaggerEventSources.OnTextChanged(subjectBuffer));
}

protected ITagSpan<TTag>? CreateTagSpan(Workspace workspace, SnapshotSpan span, DiagnosticData data)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved from intermediary subclass to this type. methods unchanged.

{
var errorTag = CreateTag(workspace, data);
if (errorTag == null)
return null;

// Ensure the diagnostic has at least length 1. Tags must have a non-empty length in order to actually show
// up in the editor.
var adjustedSpan = AdjustSnapshotSpan(span, minimumLength: 1);
if (adjustedSpan.Length == 0)
return null;

return new TagSpan<TTag>(adjustedSpan, errorTag);
}

protected virtual SnapshotSpan AdjustSnapshotSpan(SnapshotSpan span, int minimumLength)
=> AdjustSnapshotSpan(span, minimumLength, maximumLength: int.MaxValue);

protected static SnapshotSpan AdjustSnapshotSpan(SnapshotSpan span, int minimumLength, int maximumLength)
{
var snapshot = span.Snapshot;

// new length
var length = Math.Min(Math.Max(span.Length, minimumLength), maximumLength);

// make sure start + length is smaller than snapshot.Length and start is >= 0
var start = Math.Max(0, Math.Min(span.Start, snapshot.Length - length));

// make sure length is smaller than snapshot.Length which can happen if start == 0
return new SnapshotSpan(snapshot, start, Math.Min(start + length, snapshot.Length) - start);
}
}
Loading
Loading