提交 29a4338e 编写于 作者: C CyrusNajmabadi

Be resilient to the document being shorter than when it started when we get a...

Be resilient to the document being shorter than when it started when we get a completoin item description.
上级 ec1cde8b
// 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.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.CSharp.Completion.Providers;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.VisualStudio.Text;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -320,5 +322,38 @@ class C { void M() { B.$$ } }
await VerifyItemExistsAsync(code, "X");
await VerifyItemExistsAsync(code, "Y");
}
[WorkItem(209299, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=209299")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestDescriptionWhenDocumentLengthChanges()
{
var code = @"using System;
class C
{
string Property
{
get
{
Console.$$";//, @"Beep"
using (var workspace = TestWorkspace.CreateCSharp(code))
{
var testDocument = workspace.Documents.Single();
var position = testDocument.CursorPosition.Value;
var document = workspace.CurrentSolution.GetDocument(testDocument.Id);
var service = CompletionService.GetService(document);
var completions = await service.GetCompletionsAsync(document, position);
var item = completions.Items.First(i => i.DisplayText == "Beep");
var edit = testDocument.GetTextBuffer().CreateEdit();
edit.Delete(Span.FromBounds(position - 10, position));
edit.Apply();
document = workspace.CurrentSolution.GetDocument(testDocument.Id);
var description = service.GetDescriptionAsync(document, item);
}
}
}
}
......@@ -11,9 +11,10 @@ abstract class AbstractCrefCompletionProvider : CommonCompletionProvider
{
protected const string HideAdvancedMembers = nameof(HideAdvancedMembers);
protected override async Task<CompletionDescription> GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
protected override async Task<CompletionDescription> GetDescriptionWorkerAsync(
Document document, CompletionItem item, CancellationToken cancellationToken)
{
var position = SymbolCompletionItem.GetContextPosition(item);
var position = await SymbolCompletionItem.GetContextPositionAsync(document, item, cancellationToken).ConfigureAwait(false);
// What EditorBrowsable settings were we previously passed in (if it mattered)?
bool hideAdvancedMembers = false;
......
......@@ -108,7 +108,7 @@ private static int ComputeSymbolMatchPriority(ISymbol symbol)
protected override async Task<CompletionDescription> GetDescriptionWorkerAsync(
Document document, CompletionItem item, CancellationToken cancellationToken)
{
var position = SymbolCompletionItem.GetContextPosition(item);
var position = await SymbolCompletionItem.GetContextPositionAsync(document, item, cancellationToken).ConfigureAwait(false);
var name = SymbolCompletionItem.GetSymbolName(item);
var kind = SymbolCompletionItem.GetKind(item);
var relatedDocumentIds = document.Project.Solution.GetRelatedDocumentIds(document.Id).Concat(document.Id);
......
......@@ -8,6 +8,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Completion.Providers
{
......@@ -144,11 +145,12 @@ private static ISymbol DecodeSymbol(string id, Compilation compilation)
return SymbolKey.Resolve(id, compilation).GetAnySymbol();
}
public static async Task<CompletionDescription> GetDescriptionAsync(CompletionItem item, Document document, CancellationToken cancellationToken)
public static async Task<CompletionDescription> GetDescriptionAsync(
CompletionItem item, Document document, CancellationToken cancellationToken)
{
var workspace = document.Project.Solution.Workspace;
var position = GetDescriptionPosition(item);
var position = await GetDescriptionPositionAsync(document, item, cancellationToken).ConfigureAwait(false);
if (position == -1)
{
position = item.Span.Start;
......@@ -214,11 +216,19 @@ public static SupportedPlatformData GetSupportedPlatforms(CompletionItem item, W
return null;
}
public static int GetContextPosition(CompletionItem item)
public static async Task<int> GetContextPositionAsync(
Document document, CompletionItem item, CancellationToken cancellationToken)
{
if (item.Properties.TryGetValue("ContextPosition", out var text) && int.TryParse(text, out var number))
if (item.Properties.TryGetValue("ContextPosition", out var text) &&
int.TryParse(text, out var number))
{
return number;
// We have no access to the editor at this layer. So it's not
// possible for us to map the original context position forward
// to the current position in the file. So we need to cap the
// positoin to make sure it's within the bounds of the current
// text.
var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return Math.Min(number, sourceText.Length);
}
else
{
......@@ -226,10 +236,8 @@ public static int GetContextPosition(CompletionItem item)
}
}
public static int GetDescriptionPosition(CompletionItem item)
{
return GetContextPosition(item);
}
public static Task<int> GetDescriptionPositionAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
=> GetContextPositionAsync(document, item, cancellationToken);
public static string GetInsertionText(CompletionItem item)
{
......@@ -293,11 +301,12 @@ internal static string GetSymbolName(CompletionItem item)
return null;
}
public static async Task<CompletionDescription> GetDescriptionAsync(CompletionItem item, ImmutableArray<ISymbol> symbols, Document document, SemanticModel semanticModel, CancellationToken cancellationToken)
public static async Task<CompletionDescription> GetDescriptionAsync(
CompletionItem item, ImmutableArray<ISymbol> symbols, Document document, SemanticModel semanticModel, CancellationToken cancellationToken)
{
var workspace = document.Project.Solution.Workspace;
var position = SymbolCompletionItem.GetDescriptionPosition(item);
var position = await SymbolCompletionItem.GetDescriptionPositionAsync(document, item, cancellationToken).ConfigureAwait(false);
var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(item, workspace);
var contextDocument = FindAppropriateDocumentForDescriptionContext(document, supportedPlatforms);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册