提交 08afa998 编写于 作者: R Ravi Chande 提交者: GitHub

Merge branch 'dev15.4.x' into ctrl-click-gtd

......@@ -75,7 +75,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.VisualStudio.Validation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
......
......@@ -170,10 +170,10 @@
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Utilities">
<Version>$(MicrosoftVisualStudioUtilitiesVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)</Version>
</PackageReference>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)</Version>
</PackageReference>
</ItemGroup>
<Import Project="..\..\..\build\Targets\Imports.targets" />
</Project>
......@@ -73,7 +73,7 @@ internal partial class CodeFixService : ForegroundThreadAffinitizedObject, ICode
_fixAllProviderMap = ImmutableDictionary<object, FixAllProviderInfo>.Empty;
}
public async Task<FirstDiagnosticResult> GetFirstDiagnosticWithFixAsync(
public async Task<FirstDiagnosticResult> GetMostSevereFixableDiagnostic(
Document document, TextSpan range, CancellationToken cancellationToken)
{
if (document == null || !document.IsOpen())
......@@ -83,32 +83,61 @@ internal partial class CodeFixService : ForegroundThreadAffinitizedObject, ICode
using (var diagnostics = SharedPools.Default<List<DiagnosticData>>().GetPooledObject())
{
var fullResult = await _diagnosticService.TryAppendDiagnosticsForSpanAsync(document, range, diagnostics.Object, cancellationToken: cancellationToken).ConfigureAwait(false);
foreach (var diagnostic in diagnostics.Object)
using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
if (!range.IntersectsWith(diagnostic.TextSpan))
{
continue;
}
var linkedToken = linkedTokenSource.Token;
// This flag is used by SuggestedActionsSource to track what solution is was
// last able to get "full results" for.
var isFullResult = await _diagnosticService.TryAppendDiagnosticsForSpanAsync(
document, range, diagnostics.Object, cancellationToken: linkedToken).ConfigureAwait(false);
var errorDiagnostics = diagnostics.Object.Where(d => d.Severity == DiagnosticSeverity.Error);
var otherDiagnostics = diagnostics.Object.Where(d => d.Severity != DiagnosticSeverity.Error);
// Kick off a task that will determine there's an Error Diagnostic with a fixer
var errorDiagnosticsTask = Task.Run(
() => GetFirstDiagnosticWithFixAsync(document, errorDiagnostics, range, linkedToken),
linkedToken);
// Kick off a task that will determine if any non-Error Diagnostic has a fixer
var otherDiagnosticsTask = Task.Run(
() => GetFirstDiagnosticWithFixAsync(document, otherDiagnostics, range, linkedToken),
linkedToken);
// If the error diagnostics task happens to complete with a non-null result before
// the other diagnostics task, we can cancel the other task.
var diagnostic = await errorDiagnosticsTask.ConfigureAwait(false)
?? await otherDiagnosticsTask.ConfigureAwait(false);
linkedTokenSource.Cancel();
return new FirstDiagnosticResult(partialResult: !isFullResult,
hasFix: diagnostic != null,
diagnostic: diagnostic);
}
}
}
// REVIEW: 2 possible designs.
// 1. find the first fix and then return right away. if the lightbulb is actually expanded, find all fixes for the line synchronously. or
// 2. kick off a task that finds all fixes for the given range here but return once we find the first one.
// at the same time, let the task to run to finish. if the lightbulb is expanded, we just simply use the task to get all fixes.
//
// first approach is simpler, so I will implement that first. if the first approach turns out to be not good enough, then
// I will try the second approach which will be more complex but quicker
var hasFix = await ContainsAnyFix(document, diagnostic, cancellationToken).ConfigureAwait(false);
if (hasFix)
{
return new FirstDiagnosticResult(!fullResult, hasFix, diagnostic);
}
private async Task<DiagnosticData> GetFirstDiagnosticWithFixAsync(
Document document,
IEnumerable<DiagnosticData> severityGroup,
TextSpan range,
CancellationToken cancellationToken)
{
foreach (var diagnostic in severityGroup)
{
if (!range.IntersectsWith(diagnostic.TextSpan))
{
continue;
}
return new FirstDiagnosticResult(!fullResult, false, default(DiagnosticData));
if (await ContainsAnyFixAsync(document, diagnostic, cancellationToken).ConfigureAwait(false))
{
return diagnostic;
}
}
return null;
}
public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document document, TextSpan range, bool includeSuppressionFixes, CancellationToken cancellationToken)
......@@ -142,7 +171,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
foreach (var spanAndDiagnostic in aggregatedDiagnostics)
{
await AppendFixesAsync(
document, spanAndDiagnostic.Key, spanAndDiagnostic.Value,
document, spanAndDiagnostic.Key, spanAndDiagnostic.Value,
result, cancellationToken).ConfigureAwait(false);
}
......@@ -176,7 +205,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
foreach (var spanAndDiagnostic in aggregatedDiagnostics)
{
await AppendSuppressionsAsync(
document, spanAndDiagnostic.Key, spanAndDiagnostic.Value,
document, spanAndDiagnostic.Key, spanAndDiagnostic.Value,
result, cancellationToken).ConfigureAwait(false);
}
}
......@@ -267,7 +296,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
}
private async Task AppendSuppressionsAsync(
Document document, TextSpan span, IEnumerable<DiagnosticData> diagnostics,
Document document, TextSpan span, IEnumerable<DiagnosticData> diagnostics,
ArrayBuilder<CodeFixCollection> result, CancellationToken cancellationToken)
{
if (!_suppressionProvidersMap.TryGetValue(document.Project.Language, out var lazySuppressionProvider) || lazySuppressionProvider.Value == null)
......@@ -276,10 +305,10 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
}
await AppendFixesOrSuppressionsAsync(
document, span, diagnostics, result, lazySuppressionProvider.Value,
document, span, diagnostics, result, lazySuppressionProvider.Value,
hasFix: d => lazySuppressionProvider.Value.CanBeSuppressedOrUnsuppressed(d),
getFixes: dxs => lazySuppressionProvider.Value.GetSuppressionsAsync(
document, span, dxs, cancellationToken),
document, span, dxs, cancellationToken),
cancellationToken: cancellationToken).ConfigureAwait(false);
}
......@@ -293,7 +322,7 @@ public async Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document docu
Func<ImmutableArray<Diagnostic>, Task<ImmutableArray<CodeFix>>> getFixes,
CancellationToken cancellationToken)
{
var allDiagnostics =
var allDiagnostics =
await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity)
.ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false);
var diagnostics = allDiagnostics.WhereAsArray(hasFix);
......@@ -372,7 +401,7 @@ private async Task<IEnumerable<Diagnostic>> GetProjectDiagnosticsAsync(Project p
}
}
private async Task<bool> ContainsAnyFix(
private async Task<bool> ContainsAnyFixAsync(
Document document, DiagnosticData diagnostic, CancellationToken cancellationToken)
{
var workspaceFixers = ImmutableArray<CodeFixProvider>.Empty;
......@@ -387,7 +416,7 @@ private async Task<IEnumerable<Diagnostic>> GetProjectDiagnosticsAsync(Project p
}
Lazy<ISuppressionFixProvider> lazySuppressionProvider = null;
var hasSuppressionFixer =
var hasSuppressionFixer =
_suppressionProvidersMap.TryGetValue(document.Project.Language, out lazySuppressionProvider) &&
lazySuppressionProvider.Value != null;
......
......@@ -10,9 +10,8 @@ namespace Microsoft.CodeAnalysis.CodeFixes
{
internal interface ICodeFixService
{
Task<FirstDiagnosticResult> GetFirstDiagnosticWithFixAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken);
Task<ImmutableArray<CodeFixCollection>> GetFixesAsync(Document document, TextSpan textSpan, bool includeSuppressionFixes, CancellationToken cancellationToken);
CodeFixProvider GetSuppressionFixer(string language, IEnumerable<string> diagnosticIds);
Task<FirstDiagnosticResult> GetMostSevereFixableDiagnostic(Document document, TextSpan range, CancellationToken cancellationToken);
}
}
......@@ -24,14 +24,17 @@
using Microsoft.VisualStudio.Text.Editor;
using Roslyn.Utilities;
using CodeFixGroupKey = System.Tuple<Microsoft.CodeAnalysis.Diagnostics.DiagnosticData, Microsoft.CodeAnalysis.CodeActions.CodeActionPriority>;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
using CodeFixGroupKey = Tuple<DiagnosticData, CodeActionPriority>;
internal partial class SuggestedActionsSourceProvider
{
private class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource
private class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISuggestedActionsSource2
{
private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry;
// state that will be only reset when source is disposed.
private SuggestedActionsSourceProvider _owner;
private ITextView _textView;
......@@ -44,12 +47,17 @@ private class SuggestedActionsSource : ForegroundThreadAffinitizedObject, ISugge
public event EventHandler<EventArgs> SuggestedActionsChanged;
public SuggestedActionsSource(SuggestedActionsSourceProvider owner, ITextView textView, ITextBuffer textBuffer)
public SuggestedActionsSource(
SuggestedActionsSourceProvider owner,
ITextView textView,
ITextBuffer textBuffer,
ISuggestedActionCategoryRegistryService suggestedActionCategoryRegistry)
{
_owner = owner;
_textView = textView;
_textView.Closed += OnTextViewClosed;
_subjectBuffer = textBuffer;
_suggestedActionCategoryRegistry = suggestedActionCategoryRegistry;
_registration = Workspace.GetWorkspaceRegistration(textBuffer.AsTextContainer());
_lastSolutionVersionReported = InvalidSolutionVersion;
......@@ -221,7 +229,7 @@ private SuggestedActionSet FilterActionSetByTitle(SuggestedActionSet set, HashSe
{
return actions.Count == 0
? null
: new SuggestedActionSet(actions.ToImmutable(), set.Title, set.Priority, set.ApplicableToSpan);
: new SuggestedActionSet(set.CategoryName, actions.ToImmutable(), set.Title, set.Priority, set.ApplicableToSpan);
}
finally
{
......@@ -261,7 +269,11 @@ private SuggestedActionSet InlineActions(SuggestedActionSet actionSet)
}
return new SuggestedActionSet(
newActions.ToImmutableAndFree(), actionSet.Title, actionSet.Priority, actionSet.ApplicableToSpan);
actionSet.CategoryName,
newActions.ToImmutableAndFree(),
actionSet.Title,
actionSet.Priority,
actionSet.ApplicableToSpan);
}
private ImmutableArray<SuggestedActionSet> GetCodeFixes(
......@@ -529,13 +541,29 @@ private CodeRefactoring FilterOnUIThread(CodeRefactoring refactoring, Workspace
// diagnostic from things like build shouldn't reach here since we don't support LB for those diagnostics
Contract.Requires(diag.Item1.HasTextSpan);
sets.Add(new SuggestedActionSet(group, priority, diag.Item1.TextSpan.ToSpan()));
var category = GetFixCategory(diag.Item1.Severity);
sets.Add(new SuggestedActionSet(category, group, priority: priority, applicableToSpan: diag.Item1.TextSpan.ToSpan()));
}
}
return sets.ToImmutableAndFree();
}
private static string GetFixCategory(DiagnosticSeverity severity)
{
switch (severity)
{
case DiagnosticSeverity.Hidden:
case DiagnosticSeverity.Info:
case DiagnosticSeverity.Warning:
return PredefinedSuggestedActionCategoryNames.CodeFix;
case DiagnosticSeverity.Error:
return PredefinedSuggestedActionCategoryNames.ErrorFix;
default:
throw ExceptionUtilities.Unreachable;
};
}
private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActionPriority key)
{
switch (key)
......@@ -619,87 +647,81 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
}
return new SuggestedActionSet(
PredefinedSuggestedActionCategoryNames.Refactoring,
refactoringSuggestedActions.ToImmutableAndFree(),
SuggestedActionSetPriority.Low,
applicableSpan);
priority: SuggestedActionSetPriority.Low,
applicableToSpan: applicableSpan);
}
public async Task<bool> HasSuggestedActionsAsync(
public Task<bool> HasSuggestedActionsAsync(
ISuggestedActionCategorySet requestedActionCategories,
SnapshotSpan range,
CancellationToken cancellationToken)
{
var provider = _owner;
// We implement GetSuggestedActionCategoriesAsync so this should not be called
throw new NotImplementedException($"We implement {nameof(GetSuggestedActionCategoriesAsync)}. This should not be called.");
}
if (IsDisposed)
private async Task<TextSpan?> GetSpanAsync(SnapshotSpan range)
{
// First, ensure that the snapshot we're being asked about is for an actual
// roslyn document. This can fail, for example, in projection scenarios where
// we are called with a range snapshot that refers to the projection buffer
// and not the actual roslyn code that is being projected into it.
var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document == null)
{
// We've already been disposed. No point in continuing.
return false;
return null;
}
using (var asyncToken = _owner.OperationListener.BeginAsyncOperation("HasSuggestedActionsAsync"))
{
// First, ensure that the snapshot we're being asked about is for an actual
// roslyn document. This can fail, for example, in projection scenarios where
// we are called with a range snapshot that refers to the projection buffer
// and not the actual roslyn code that is being projected into it.
var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document == null)
{
return false;
}
// Next, before we do any async work, acquire the user's selection, directly grabbing
// it from the UI thread if htat's what we're on. That way we don't have any reentrancy
// blocking concerns if VS wants to block on this call (for example, if the user
// explicitly invokes the 'show smart tag' command).
//
// This work must happen on the UI thread as it needs to access the _textView's mutable
// state.
//
// Note: we may be called in one of two VS scenarios:
// 1) User has moved caret to a new line. In this case VS will call into us in the
// bg to see if we have any suggested actions for this line. In order to figure
// this out, we need to see what selectoin the user has (for refactorings), which
// necessitates going back to the fg.
//
// 2) User moves to a line and immediately hits ctrl-dot. In this case, on the UI
// thread VS will kick us off and then immediately block to get the results so
// that they can expand the lightbulb. In this case we cannot do BG work first,
// then call back into the UI thread to try to get the user selection. This will
// deadlock as the UI thread is blocked on us.
//
// There are two solution to '2'. Either introduce reentrancy (which we really don't
// like to do), or just ensure that we acquire and get the users selection up front.
// This means that when we're called from the UI therad, we never try to go back to the
// UI thread.
TextSpan? selection = null;
if (IsForeground())
{
selection = TryGetCodeRefactoringSelection(range);
}
else
// Next, before we do any async work, acquire the user's selection, directly grabbing
// it from the UI thread if htat's what we're on. That way we don't have any reentrancy
// blocking concerns if VS wants to block on this call (for example, if the user
// explicitly invokes the 'show smart tag' command).
//
// This work must happen on the UI thread as it needs to access the _textView's mutable
// state.
//
// Note: we may be called in one of two VS scenarios:
// 1) User has moved caret to a new line. In this case VS will call into us in the
// bg to see if we have any suggested actions for this line. In order to figure
// this out, we need to see what selectoin the user has (for refactorings), which
// necessitates going back to the fg.
//
// 2) User moves to a line and immediately hits ctrl-dot. In this case, on the UI
// thread VS will kick us off and then immediately block to get the results so
// that they can expand the lightbulb. In this case we cannot do BG work first,
// then call back into the UI thread to try to get the user selection. This will
// deadlock as the UI thread is blocked on us.
//
// There are two solution to '2'. Either introduce reentrancy (which we really don't
// like to do), or just ensure that we acquire and get the users selection up front.
// This means that when we're called from the UI therad, we never try to go back to the
// UI thread.
TextSpan? selection = null;
if (IsForeground())
{
selection = TryGetCodeRefactoringSelection(range);
}
else
{
await InvokeBelowInputPriority(() =>
{
await InvokeBelowInputPriority(() =>
// Make sure we were not disposed between kicking off this work and getting
// to this point.
if (IsDisposed)
{
// Make sure we were not disposed between kicking off this work and getting
// to this point.
if (IsDisposed)
{
return;
}
selection = TryGetCodeRefactoringSelection(range);
}).ConfigureAwait(false);
}
return;
}
return
await HasFixesAsync(provider, document, range, cancellationToken).ConfigureAwait(false) ||
await HasRefactoringsAsync(provider, document, selection, cancellationToken).ConfigureAwait(false);
selection = TryGetCodeRefactoringSelection(range);
}).ConfigureAwait(false);
}
return selection;
}
private async Task<bool> HasFixesAsync(
private async Task<string> GetFixLevelAsync(
SuggestedActionsSourceProvider provider,
Document document,
SnapshotSpan range,
......@@ -712,28 +734,28 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
supportsFeatureService.SupportsCodeFixes(document))
{
var result = await Task.Run(
() => provider._codeFixService.GetFirstDiagnosticWithFixAsync(
() => provider._codeFixService.GetMostSevereFixableDiagnostic(
document, range.Span.ToTextSpan(), cancellationToken),
cancellationToken).ConfigureAwait(false);
if (result.HasFix)
{
Logger.Log(FunctionId.SuggestedActions_HasSuggestedActionsAsync);
return true;
return GetFixCategory(result.Diagnostic.Severity);
}
if (result.PartialResult)
{
// reset solution version number so that we can raise suggested action changed event
Volatile.Write(ref _lastSolutionVersionReported, InvalidSolutionVersion);
return false;
return null;
}
}
return false;
return null;
}
private async Task<bool> HasRefactoringsAsync(
private async Task<string> TryGetRefactoringSuggestedActionCategoryAsync(
SuggestedActionsSourceProvider provider,
Document document,
TextSpan? selection,
......@@ -743,7 +765,7 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
{
// this is here to fail test and see why it is failed.
Trace.WriteLine("given range is not current");
return false;
return null;
}
var workspace = document.Project.Solution.Workspace;
......@@ -753,13 +775,16 @@ private static SuggestedActionSetPriority GetSuggestedActionSetPriority(CodeActi
provider._codeRefactoringService != null &&
supportsFeatureService.SupportsRefactorings(document))
{
return await Task.Run(
if (await Task.Run(
() => provider._codeRefactoringService.HasRefactoringsAsync(
document, selection.Value, cancellationToken),
cancellationToken).ConfigureAwait(false);
cancellationToken).ConfigureAwait(false))
{
return PredefinedSuggestedActionCategoryNames.Refactoring;
}
}
return false;
return null;
}
private TextSpan? TryGetCodeRefactoringSelection(SnapshotSpan range)
......@@ -860,6 +885,40 @@ private void OnSuggestedActionsChanged(Workspace currentWorkspace, DocumentId cu
Volatile.Write(ref _lastSolutionVersionReported, solutionVersion);
}
public async Task<ISuggestedActionCategorySet> GetSuggestedActionCategoriesAsync(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken)
{
var provider = _owner;
using (var asyncToken = _owner.OperationListener.BeginAsyncOperation(nameof(GetSuggestedActionCategoriesAsync)))
{
var selection = await GetSpanAsync(range).ConfigureAwait(false);
if (selection != null)
{
var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
var linkedToken = linkedTokenSource.Token;
var errorTask = Task.Run(
() => GetFixLevelAsync(provider, document, range, linkedToken), linkedToken);
var refactoringTask = Task.Run(
() => TryGetRefactoringSuggestedActionCategoryAsync(provider, document, selection, linkedToken),
linkedToken);
// If we happen to get the result of the error task before the refactoring task,
// and that result is non-null, we can just cancel the refactoring task.
var result = await errorTask.ConfigureAwait(false) ?? await refactoringTask.ConfigureAwait(false);
linkedTokenSource.Cancel();
return result == null
? null
: _suggestedActionCategoryRegistry.CreateSuggestedActionCategorySet(result);
}
}
}
return null;
}
}
}
}
\ No newline at end of file
......@@ -35,6 +35,7 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
private readonly ICodeRefactoringService _codeRefactoringService;
private readonly IDiagnosticAnalyzerService _diagnosticService;
private readonly ICodeFixService _codeFixService;
private readonly ISuggestedActionCategoryRegistryService _suggestedActionCategoryRegistry;
public readonly ICodeActionEditHandlerService EditHandler;
public readonly IAsynchronousOperationListener OperationListener;
......@@ -50,6 +51,7 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
ICodeFixService codeFixService,
ICodeActionEditHandlerService editHandler,
IWaitIndicator waitIndicator,
ISuggestedActionCategoryRegistryService suggestedActionCategoryRegistry,
[ImportMany] IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners,
[ImportMany] IEnumerable<Lazy<IImageMonikerService, OrderableMetadata>> imageMonikerServices,
[ImportMany] IEnumerable<Lazy<ISuggestedActionCallback>> actionCallbacks)
......@@ -57,6 +59,7 @@ internal partial class SuggestedActionsSourceProvider : ISuggestedActionsSourceP
_codeRefactoringService = codeRefactoringService;
_diagnosticService = diagnosticService;
_codeFixService = codeFixService;
_suggestedActionCategoryRegistry = suggestedActionCategoryRegistry;
ActionCallbacks = actionCallbacks.ToImmutableArray();
EditHandler = editHandler;
WaitIndicator = waitIndicator;
......@@ -70,7 +73,7 @@ public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView,
Contract.ThrowIfNull(textView);
Contract.ThrowIfNull(textBuffer);
return new SuggestedActionsSource(this, textView, textBuffer);
return new SuggestedActionsSource(this, textView, textBuffer, _suggestedActionCategoryRegistry);
}
}
}
\ No newline at end of file
......@@ -46,7 +46,7 @@ public async Task TestGetFirstDiagnosticWithFixAsync()
var reference = new MockAnalyzerReference();
var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference);
var document = project.Documents.Single();
var unused = await fixService.GetFirstDiagnosticWithFixAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None);
var unused = await fixService.GetMostSevereFixableDiagnostic(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None);
var fixer1 = fixers.Single().Value as MockFixer;
var fixer2 = reference.Fixer as MockFixer;
......@@ -127,7 +127,7 @@ public async Task GetFirstDiagnosticWithFixAsync(CodeFixProvider codefix)
using (var workspace = tuple.Item1)
{
GetDocumentAndExtensionManager(tuple.Item2, workspace, out var document, out var extensionManager);
var unused = await tuple.Item3.GetFirstDiagnosticWithFixAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None);
var unused = await tuple.Item3.GetMostSevereFixableDiagnostic(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None);
Assert.True(extensionManager.IsDisabled(codefix));
Assert.False(extensionManager.IsIgnored(codefix));
}
......
......@@ -20,6 +20,7 @@ Microsoft.VisualStudio.Utilities.dll
Microsoft.VisualStudio.Platform.VSEditor.dll
Microsoft.VisualStudio.Platform.VSEditor.Interop.dll
Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll
Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.dll
Microsoft.Internal.Performance.CodeMarkers.DesignTime.dll
PackageAndDeploy\Microsoft.VisualStudio.Shell.Framework.dll
PackageAndDeploy\Microsoft.VisualStudio.Shell.15.0.dll
......
......@@ -345,6 +345,9 @@
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop150DesignTimeVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0">
<Version>$(MicrosoftVisualStudioShell150Version)</Version>
......
......@@ -126,12 +126,15 @@
<PackageReference Include="Microsoft.VisualStudio.Diagnostics.PerformanceProvider">
<Version>$(MicrosoftVisualStudioDiagnosticsPerformanceProviderVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)</Version>
</PackageReference>
<PackageReference Include="StreamJsonRPC">
<PackageReference Include="StreamJsonRPC">
<Version>$(StreamJsonRPCVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Threading">
<Version>$(MicrosoftVisualStudioThreadingVersion)</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<PublicAPI Include="PublicAPI.Shipped.txt" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册