Skip to content

Commit

Permalink
Merge pull request #20554 from DustinCampbell/new-quick-info-api
Browse files Browse the repository at this point in the history
New Quick Info API
  • Loading branch information
DustinCampbell authored Feb 16, 2018
2 parents 7206c3b + b9f774b commit 8985690
Show file tree
Hide file tree
Showing 120 changed files with 1,960 additions and 1,772 deletions.
21 changes: 0 additions & 21 deletions src/EditorFeatures/CSharp/QuickInfo/SemanticQuickInfoProvider.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor.CSharp.QuickInfo;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.CodeAnalysis.QuickInfo;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
Expand All @@ -22,24 +18,24 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.QuickInfo
{
public class SemanticQuickInfoSourceTests : AbstractSemanticQuickInfoSourceTests
{
private async Task TestWithOptionsAsync(CSharpParseOptions options, string markup, params Action<object>[] expectedResults)
private async Task TestWithOptionsAsync(CSharpParseOptions options, string markup, params Action<QuickInfoItem>[] expectedResults)
{
using (var workspace = TestWorkspace.CreateCSharp(markup, options))
{
await TestWithOptionsAsync(workspace, expectedResults);
}
}

private async Task TestWithOptionsAsync(TestWorkspace workspace, params Action<object>[] expectedResults)
private async Task TestWithOptionsAsync(TestWorkspace workspace, params Action<QuickInfoItem>[] expectedResults)
{
var testDocument = workspace.DocumentWithCursor;
var position = testDocument.CursorPosition.GetValueOrDefault();
var documentId = workspace.GetDocumentId(testDocument);
var document = workspace.CurrentSolution.GetDocument(documentId);

var provider = new SemanticQuickInfoProvider();
var service = QuickInfoService.GetService(document);

await TestWithOptionsAsync(document, provider, position, expectedResults);
await TestWithOptionsAsync(document, service, position, expectedResults);

// speculative semantic model
if (await CanUseSpeculativeSemanticModelAsync(document, position))
Expand All @@ -52,34 +48,30 @@ private async Task TestWithOptionsAsync(TestWorkspace workspace, params Action<o
edit.Apply();
}

await TestWithOptionsAsync(document, provider, position, expectedResults);
await TestWithOptionsAsync(document, service, position, expectedResults);
}
}

private async Task TestWithOptionsAsync(Document document, SemanticQuickInfoProvider provider, int position, Action<object>[] expectedResults)
private async Task TestWithOptionsAsync(Document document, QuickInfoService service, int position, Action<QuickInfoItem>[] expectedResults)
{
var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None);
if (state != null)
{
WaitForDocumentationComment(state.Content);
}
var info = await service.GetQuickInfoAsync(document, position, cancellationToken: CancellationToken.None);

if (expectedResults.Length == 0)
{
Assert.Null(state);
Assert.Null(info);
}
else
{
Assert.NotNull(state);
Assert.NotNull(info);

foreach (var expected in expectedResults)
{
expected(state.Content);
expected(info);
}
}
}

private async Task VerifyWithMscorlib45Async(string markup, Action<object>[] expectedResults)
private async Task VerifyWithMscorlib45Async(string markup, Action<QuickInfoItem>[] expectedResults)
{
var xmlString = string.Format(@"
<Workspace>
Expand All @@ -96,37 +88,33 @@ private async Task VerifyWithMscorlib45Async(string markup, Action<object>[] exp
var documentId = workspace.Documents.Where(d => d.Name == "SourceDocument").Single().Id;
var document = workspace.CurrentSolution.GetDocument(documentId);

var provider = new SemanticQuickInfoProvider();
var service = QuickInfoService.GetService(document);

var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None);
if (state != null)
{
WaitForDocumentationComment(state.Content);
}
var info = await service.GetQuickInfoAsync(document, position, cancellationToken: CancellationToken.None);

if (expectedResults.Length == 0)
{
Assert.Null(state);
Assert.Null(info);
}
else
{
Assert.NotNull(state);
Assert.NotNull(info);

foreach (var expected in expectedResults)
{
expected(state.Content);
expected(info);
}
}
}
}

protected override async Task TestAsync(string markup, params Action<object>[] expectedResults)
protected override async Task TestAsync(string markup, params Action<QuickInfoItem>[] expectedResults)
{
await TestWithOptionsAsync(Options.Regular, markup, expectedResults);
await TestWithOptionsAsync(Options.Script, markup, expectedResults);
}

protected async Task TestWithUsingsAsync(string markup, params Action<object>[] expectedResults)
private async Task TestWithUsingsAsync(string markup, params Action<QuickInfoItem>[] expectedResults)
{
var markupWithUsings =
@"using System;
Expand All @@ -137,13 +125,13 @@ protected async Task TestWithUsingsAsync(string markup, params Action<object>[]
await TestAsync(markupWithUsings, expectedResults);
}

protected Task TestInClassAsync(string markup, params Action<object>[] expectedResults)
private Task TestInClassAsync(string markup, params Action<QuickInfoItem>[] expectedResults)
{
var markupInClass = "class C { " + markup + " }";
return TestWithUsingsAsync(markupInClass, expectedResults);
}

protected Task TestInMethodAsync(string markup, params Action<object>[] expectedResults)
private Task TestInMethodAsync(string markup, params Action<QuickInfoItem>[] expectedResults)
{
var markupInMethod = "class C { void M() { " + markup + " } }";
return TestWithUsingsAsync(markupInMethod, expectedResults);
Expand All @@ -153,7 +141,7 @@ private async Task TestWithReferenceAsync(string sourceCode,
string referencedCode,
string sourceLanguage,
string referencedLanguage,
params Action<object>[] expectedResults)
params Action<QuickInfoItem>[] expectedResults)
{
await TestWithMetadataReferenceHelperAsync(sourceCode, referencedCode, sourceLanguage, referencedLanguage, expectedResults);
await TestWithProjectReferenceHelperAsync(sourceCode, referencedCode, sourceLanguage, referencedLanguage, expectedResults);
Expand All @@ -170,7 +158,7 @@ private async Task TestWithMetadataReferenceHelperAsync(
string referencedCode,
string sourceLanguage,
string referencedLanguage,
params Action<object>[] expectedResults)
params Action<QuickInfoItem>[] expectedResults)
{
var xmlString = string.Format(@"
<Workspace>
Expand All @@ -195,7 +183,7 @@ private async Task TestWithProjectReferenceHelperAsync(
string referencedCode,
string sourceLanguage,
string referencedLanguage,
params Action<object>[] expectedResults)
params Action<QuickInfoItem>[] expectedResults)
{
var xmlString = string.Format(@"
<Workspace>
Expand All @@ -221,7 +209,7 @@ private async Task TestInSameProjectHelperAsync(
string sourceCode,
string referencedCode,
string sourceLanguage,
params Action<object>[] expectedResults)
params Action<QuickInfoItem>[] expectedResults)
{
var xmlString = string.Format(@"
<Workspace>
Expand All @@ -238,33 +226,29 @@ private async Task TestInSameProjectHelperAsync(
await VerifyWithReferenceWorkerAsync(xmlString, expectedResults);
}

private async Task VerifyWithReferenceWorkerAsync(string xmlString, params Action<object>[] expectedResults)
private async Task VerifyWithReferenceWorkerAsync(string xmlString, params Action<QuickInfoItem>[] expectedResults)
{
using (var workspace = TestWorkspace.Create(xmlString))
{
var position = workspace.Documents.First(d => d.Name == "SourceDocument").CursorPosition.Value;
var documentId = workspace.Documents.First(d => d.Name == "SourceDocument").Id;
var document = workspace.CurrentSolution.GetDocument(documentId);

var provider = new SemanticQuickInfoProvider();
var service = QuickInfoService.GetService(document);

var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None);
if (state != null)
{
WaitForDocumentationComment(state.Content);
}
var info = await service.GetQuickInfoAsync(document, position, cancellationToken: CancellationToken.None);

if (expectedResults.Length == 0)
{
Assert.Null(state);
Assert.Null(info);
}
else
{
Assert.NotNull(state);
Assert.NotNull(info);

foreach (var expected in expectedResults)
{
expected(state.Content);
expected(info);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor.CSharp.QuickInfo;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo;
using Microsoft.CodeAnalysis.Editor.QuickInfo;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.CSharp.QuickInfo;
using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.CodeAnalysis.QuickInfo;
using Roslyn.Test.Utilities;
using Xunit;

Expand Down Expand Up @@ -263,9 +258,9 @@ await TestInMethodAndScriptAsync(
{");
}

private IQuickInfoProvider CreateProvider(TestWorkspace workspace)
private QuickInfoProvider CreateProvider(TestWorkspace workspace)
{
return new SyntacticQuickInfoProvider();
return new CSharpSyntacticQuickInfoProvider();
}

protected override async Task AssertNoContentAsync(
Expand All @@ -274,7 +269,7 @@ protected override async Task AssertNoContentAsync(
int position)
{
var provider = CreateProvider(workspace);
Assert.Null(await provider.GetItemAsync(document, position, CancellationToken.None));
Assert.Null(await provider.GetQuickInfoAsync(new QuickInfoContext(document, position, CancellationToken.None)));
}

protected override async Task AssertContentIsAsync(
Expand All @@ -285,14 +280,15 @@ protected override async Task AssertContentIsAsync(
string expectedDocumentationComment = null)
{
var provider = CreateProvider(workspace);
var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None);
Assert.NotNull(state);

var hostingControlFactory = workspace.GetService<DeferredContentFrameworkElementFactory>();

var viewHostingControl = (ViewHostingControl)hostingControlFactory.CreateElement(state.Content);
var actualContent = viewHostingControl.GetText_TestOnly();
Assert.Equal(expectedContent, actualContent);
var info = await provider.GetQuickInfoAsync(new QuickInfoContext(document, position, CancellationToken.None));
Assert.NotNull(info);

Assert.NotEqual(0, info.RelatedSpans.Length);
var tabSize = document.Project.Solution.Workspace.Options.GetOption(Microsoft.CodeAnalysis.Formatting.FormattingOptions.TabSize, document.Project.Language);
var text = await document.GetTextAsync();
var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, info.RelatedSpans, tabSize);
var actualText = string.Concat(spans.Select(s => text.GetSubText(s).ToString()));
Assert.Equal(expectedContent, actualText);
}

protected override Task TestInMethodAsync(string code, string expectedContent, string expectedDocumentationComment = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Wpf;
using Microsoft.CodeAnalysis.Tags;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Imaging.Interop;
using Microsoft.VisualStudio.Language.Intellisense;
Expand All @@ -31,7 +32,7 @@ public CustomCommitCompletion(
// extra allocation is avoided.
_completionPresenterSession = completionPresenterSession;
this.CompletionItem = completionItem;
_imageMoniker = ImageMonikers.GetImageMoniker(CompletionItem.Tags);
_imageMoniker = ImageMonikers.GetFirstImageMoniker(CompletionItem.Tags);
}

public void Commit()
Expand Down Expand Up @@ -74,7 +75,7 @@ public override IEnumerable<CompletionIcon> AttributeIcons
{
get
{
if (this.CompletionItem.Tags.Contains(CompletionTags.Warning))
if (this.CompletionItem.Tags.Contains(WellKnownTags.Warning))
{
return new[] { new CompletionIcon2(Glyph.CompletionWarning.GetImageMoniker(), s_glyphCompletionWarning, s_glyphCompletionWarning) };
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
// 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.Collections.Immutable;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Wpf;
using Microsoft.VisualStudio.Imaging.Interop;

namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.Presentation
{
internal static class ImageMonikers
{
public static ImageMoniker GetImageMoniker(ImmutableArray<string> tags)
public static ImageMoniker GetFirstImageMoniker(ImmutableArray<string> tags)
{
return tags.GetGlyph().GetImageMoniker();
return tags.GetFirstGlyph().GetImageMoniker();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal class IntellisenseFilter2 : IntellisenseFilter

public IntellisenseFilter2(
RoslynCompletionSet completionSet, CompletionItemFilter filter)
: base(ImageMonikers.GetImageMoniker(filter.Tags), GetToolTip(filter),
: base(ImageMonikers.GetFirstImageMoniker(filter.Tags), GetToolTip(filter),
filter.AccessKey.ToString(), automationText: filter.Tags[0])
{
_completionSet = completionSet;
Expand Down
Loading

0 comments on commit 8985690

Please sign in to comment.