未验证 提交 6098451e 编写于 作者: A Abhitej John 提交者: GitHub

Merge pull request #24828 from dotnet/merges/dev15.6.x-to-dev15.7.x

Merge dev15.6.x to dev15.7.x
......@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.Undo;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Options;
......@@ -153,6 +154,20 @@ private void OnBeforeDebuggingStateChanged(object sender, DebuggingStateChangedE
public string OriginalSymbolName => _renameInfo.DisplayName;
// Used to aid the investigation of https://github.com/dotnet/roslyn/issues/7364
private class NullTextBufferException : Exception
{
private readonly Document _document;
private readonly SourceText _text;
public NullTextBufferException(Document document, SourceText text)
: base("Cannot retrieve textbuffer from document.")
{
_document = document;
_text = text;
}
}
private void InitializeOpenBuffers(SnapshotSpan triggerSpan)
{
using (Logger.LogBlock(FunctionId.Rename_CreateOpenTextBufferManagerForAllOpenDocs, CancellationToken.None))
......@@ -165,7 +180,11 @@ private void InitializeOpenBuffers(SnapshotSpan triggerSpan)
Contract.ThrowIfNull(text);
var textSnapshot = text.FindCorrespondingEditorTextSnapshot();
Contract.ThrowIfNull(textSnapshot);
if (textSnapshot == null)
{
FatalError.ReportWithoutCrash(new NullTextBufferException(document, text));
continue;
}
Contract.ThrowIfNull(textSnapshot.TextBuffer);
openBuffers.Add(textSnapshot.TextBuffer);
......
// 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.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Common;
......@@ -9,6 +10,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Tagging;
using Microsoft.CodeAnalysis.Editor.Tagging;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
......@@ -36,6 +38,16 @@ internal abstract partial class AbstractDiagnosticsTaggerProvider<TTag> : Asynch
{
private readonly IDiagnosticService _diagnosticService;
/// <summary>
/// Keep track of the ITextSnapshot for the open Document that was used when diagnostics were
/// produced for it. We need that because the DiagnoticService does not keep track of this
/// snapshot (so as to not hold onto a lot of memory), which means when we query it for
/// diagnostics, we don't know how to map the span of the diagnostic to the current snapshot
/// we're tagging.
/// </summary>
private static readonly ConditionalWeakTable<object, ITextSnapshot> _diagnosticIdToTextSnapshot =
new ConditionalWeakTable<object, ITextSnapshot>();
protected AbstractDiagnosticsTaggerProvider(
IDiagnosticService diagnosticService,
IForegroundNotificationService notificationService,
......@@ -43,6 +55,40 @@ internal abstract partial class AbstractDiagnosticsTaggerProvider<TTag> : Asynch
: base(listener, notificationService)
{
_diagnosticService = diagnosticService;
_diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated;
}
private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e)
{
if (e.Solution == null || e.DocumentId == null)
{
return;
}
if (_diagnosticIdToTextSnapshot.TryGetValue(e.Id, out var snapshot))
{
return;
}
var document = e.Solution.GetDocument(e.DocumentId);
// Open documents *should* always have their SourceText available, but we cannot guarantee
// (i.e. assert) that they do. That's because we're not on the UI thread here, so there's
// a small risk that between calling .IsOpen the file may then close, which then would
// cause TryGetText to fail. However, that's ok. In that case, if we do need to tag this
// document, we'll just use the current editor snapshot. If that's the same, then the tags
// will be hte same. If it is different, we'll eventually hear about the new diagnostics
// for it and we'll reach our fixed point.
if (document != null && document.IsOpen())
{
// This should always be fast since the document is open.
var sourceText = document.State.GetTextSynchronously(cancellationToken: default);
snapshot = sourceText.FindCorrespondingEditorTextSnapshot();
if (snapshot != null)
{
_diagnosticIdToTextSnapshot.GetValue(e.Id, _ => snapshot);
}
}
}
protected override TaggerDelay AddedTagNotificationDelay => TaggerDelay.OnIdle;
......@@ -93,18 +139,17 @@ private void ProduceTags(TaggerContext<TTag> context, DocumentSnapshotSpan spanT
var eventArgs = _diagnosticService.GetDiagnosticsUpdatedEventArgs(
workspace, document.Project.Id, document.Id, context.CancellationToken);
var sourceText = editorSnapshot.AsText();
foreach (var updateArg in eventArgs)
{
ProduceTags(
context, spanToTag, workspace, document, sourceText,
context, spanToTag, workspace, document,
suppressedDiagnosticsSpans, updateArg, cancellationToken);
}
}
private void ProduceTags(
TaggerContext<TTag> context, DocumentSnapshotSpan spanToTag,
Workspace workspace, Document document, SourceText sourceText,
Workspace workspace, Document document,
NormalizedSnapshotSpanCollection suppressedDiagnosticsSpans,
UpdatedEventArgs updateArgs, CancellationToken cancellationToken)
{
......@@ -119,6 +164,24 @@ private void ProduceTags(TaggerContext<TTag> context, DocumentSnapshotSpan spanT
var requestedSpan = spanToTag.SnapshotSpan;
var editorSnapshot = requestedSpan.Snapshot;
// Try to get the text snapshot that these diagnostics were created against.
// This may fail if this tagger was created *after* the notification for the
// diagnostics was already issued. That's ok. We'll take the spans as reported
// and apply them directly to the snapshot we have. Either no new changes will
// have happened, and these spans will be accurate, or a change will happen
// and we'll hear about and it update the spans shortly to the right position.
//
// Also, only use the diagnoticSnapshot if its text buffer matches our. The text
// buffer might be different if the file was closed/reopened.
// Note: when this happens, the diagnostic service will reanalyze the file. So
// up to date diagnostic spans will appear shortly after this.
_diagnosticIdToTextSnapshot.TryGetValue(id, out var diagnosticSnapshot);
diagnosticSnapshot = diagnosticSnapshot?.TextBuffer == editorSnapshot.TextBuffer
? diagnosticSnapshot
: editorSnapshot;
var sourceText = diagnosticSnapshot.AsText();
foreach (var diagnosticData in diagnostics)
{
if (this.IncludeDiagnostic(diagnosticData))
......@@ -135,7 +198,8 @@ private void ProduceTags(TaggerContext<TTag> context, DocumentSnapshotSpan spanT
// editorSnapshot.
var diagnosticSpan = diagnosticData.GetExistingOrCalculatedTextSpan(sourceText)
.ToSnapshotSpan(editorSnapshot);
.ToSnapshotSpan(diagnosticSnapshot)
.TranslateTo(editorSnapshot, SpanTrackingMode.EdgeExclusive);
if (diagnosticSpan.IntersectsWith(requestedSpan) &&
!IsSuppressed(suppressedDiagnosticsSpans, diagnosticSpan))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册