提交 a1cff112 编写于 作者: P Pilchie

Add support for IVsLanguageBlock.GetCurrentBlock

Fixes internal TFS bug 1043580.
上级 e4f6411d
......@@ -122,6 +122,7 @@ public static class Features
public const string TodoComments = "TodoComments";
public const string TypeInferenceService = "TypeInferenceService";
public const string Venus = "Venus";
public const string VsLanguageBlock = "VsLanguageBlock";
public const string XmlTagCompletion = "XmlTagCompletion";
}
}
......
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
using Microsoft.VisualStudio.Text;
using Roslyn.Utilities;
using IVsLanguageBlock = Microsoft.VisualStudio.TextManager.Interop.IVsLanguageBlock;
using IVsTextLines = Microsoft.VisualStudio.TextManager.Interop.IVsTextLines;
using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
{
internal abstract partial class AbstractLanguageService<TPackage, TLanguageService>
: IVsLanguageBlock
{
public int GetCurrentBlock(
IVsTextLines pTextLines,
int iCurrentLine,
int iCurrentChar,
VsTextSpan[] ptsBlockSpan,
out string pbstrDescription,
out int pfBlockAvailable)
{
var foundBlock = false;
string description = null;
var span = default(TextSpan);
var snapshot = this.EditorAdaptersFactoryService.GetDataBuffer(pTextLines).CurrentSnapshot;
var position = snapshot.GetPosition(iCurrentLine, iCurrentChar);
var waitIndicator = this.Package.ComponentModel.GetService<IWaitIndicator>();
waitIndicator.Wait(
ServicesVSResources.CurrentBlock,
ServicesVSResources.DeterminingCurrentBlock,
allowCancel: true,
action: context =>
{
foundBlock = VsLanguageBlock.GetCurrentBlock(snapshot, position, context.CancellationToken, ref description, ref span);
});
pfBlockAvailable = foundBlock ? 1 : 0;
pbstrDescription = description;
if (ptsBlockSpan != null && ptsBlockSpan.Length >= 1)
{
ptsBlockSpan[0] = span.ToSnapshotSpan(snapshot).ToVsTextSpan();
}
return VSConstants.S_OK;
}
}
internal static class VsLanguageBlock
{
public static bool GetCurrentBlock(
ITextSnapshot snapshot,
int position,
CancellationToken cancellationToken,
ref string description,
ref TextSpan span)
{
var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();
var syntaxFactsService = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
var syntaxRoot = document.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var node = syntaxFactsService.GetContainingMemberDeclaration(syntaxRoot, position, useFullSpan: false);
if (node == null)
{
return false;
}
var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken);
if (symbol == null)
{
return false;
}
description = symbol.ToMinimalDisplayString(semanticModel, position);
span = node.Span;
return true;
}
}
}
......@@ -159,6 +159,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Current block.
/// </summary>
internal static string CurrentBlock {
get {
return ResourceManager.GetString("CurrentBlock", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Debugger.
/// </summary>
......@@ -204,6 +213,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Determining current block..
/// </summary>
internal static string DeterminingCurrentBlock {
get {
return ResourceManager.GetString("DeterminingCurrentBlock", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Get help for &apos;{0}&apos;{1}{2}{3}.
/// </summary>
......
......@@ -471,4 +471,10 @@ Use the dropdown to view and switch to other projects this file may belong to.</
<data name="FromBing" xml:space="preserve">
<value> from Bing</value>
</data>
<data name="CurrentBlock" xml:space="preserve">
<value>Current block</value>
</data>
<data name="DeterminingCurrentBlock" xml:space="preserve">
<value>Determining current block.</value>
</data>
</root>
\ No newline at end of file
......@@ -29,6 +29,7 @@
<Compile Include="Implementation\Diagnostics\VisualStudioVenusSpanMappingService.cs" />
<Compile Include="Implementation\EditAndContinue\Interop\NativeMethods.cs" />
<Compile Include="Implementation\Interop\IComWrapperFactory.cs" />
<Compile Include="Implementation\LanguageService\AbstractLanguageService`2.IVsLanguageBlock.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\AbstractSourceTreeItem.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\MetadataDefinitionTreeItem.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\SourceDefinitionTreeItem.cs" />
......
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
Imports Roslyn.Test.Utilities
Public Class LanguageBlockTests
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_NotInImports_VB()
VerifyNoBlock("
I$$mports System
Module Program
Sub M()
End Sub
End Module
", LanguageNames.VisualBasic)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_NotLeadingTriviaOfRootClass_VB()
VerifyNoBlock("
Imports System
$$
Module Program
Sub M()
End Sub
End Module
", LanguageNames.VisualBasic)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InNamespace_VB()
VerifyBlock("
[|Namespace N
$$
Module Program
Sub M()
End Sub
End Module
End Namespace|]
", LanguageNames.VisualBasic, "N")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InModule_VB()
VerifyBlock("
Namespace N
[|Module Program
$$
Sub M()
End Sub
End Module|]
End Namespace
", LanguageNames.VisualBasic, "Program")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InSub()
VerifyBlock("
Namespace N
Module Program
[|Sub M()
$$
End Sub|]
End Module
End Namespace
", LanguageNames.VisualBasic, "Sub Program.M()")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InFunction()
VerifyBlock("
Namespace N
Module Program
[|Function F() As Integer
$$
End Function|]
End Module
End Namespace
", LanguageNames.VisualBasic, "Function Program.F() As Integer")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InProperty_VB()
VerifyBlock("
Namespace N
Module Program
[|ReadOnly Property P() As Integer
Get
$$
End Get
End Property|]
End Module
End Namespace
", LanguageNames.VisualBasic, "Property Program.P As Integer")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_NotInUsings_CS()
VerifyNoBlock("
u$$sing System;
class Program
{
void M() { }
}
", LanguageNames.CSharp)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_NotLeadingTriviaOfRootClass_CS()
VerifyNoBlock("
using System;
$$
class Program
{
void M() { }
}
", LanguageNames.CSharp)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InNamespace_CS()
VerifyBlock("
[|namespace N
{
$$
class Program
{
void M() { }
}
}|]
", LanguageNames.CSharp, "N")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InClass_CS()
VerifyBlock("
namespace N
{
[|class Program
{
$$
void M() { }
}|]
}
", LanguageNames.CSharp, "Program")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InMethod()
VerifyBlock("
namespace N
{
class Program
{
[|void M()
{
$$
}|]
}
}
", LanguageNames.CSharp, "void Program.M()")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.VsLanguageBlock), WorkItem(1043580)>
Public Sub GetCurrentBlock_InProperty_CS()
VerifyBlock("
namespace N
{
class Program
{
[|public int P
{
get
{
$$
}
}|]
}
}
", LanguageNames.CSharp, "int Program.P")
End Sub
Private Sub VerifyNoBlock(markup As String, languageName As String)
Dim xml = <Workspace>
<Project Language=<%= languageName %> CommonReferences="True">
<Document>
<%= markup %>
</Document>
</Project>
</Workspace>
Using workspace = TestWorkspaceFactory.CreateWorkspace(xml)
Dim hostDocument = workspace.Documents.Single()
Dim description As String = Nothing
Dim span As TextSpan
Assert.False(VsLanguageBlock.GetCurrentBlock(
hostDocument.TextBuffer.CurrentSnapshot,
hostDocument.CursorPosition.Value,
CancellationToken.None,
description,
span))
End Using
End Sub
Private Sub VerifyBlock(markup As String, languageName As String, expectedDescription As String)
Dim xml = <Workspace>
<Project Language=<%= languageName %> CommonReferences="True">
<Document>
<%= markup %>
</Document>
</Project>
</Workspace>
Using workspace = TestWorkspaceFactory.CreateWorkspace(xml)
Dim hostDocument = workspace.Documents.Single()
Dim description As String = Nothing
Dim span As TextSpan
Assert.True(VsLanguageBlock.GetCurrentBlock(
hostDocument.TextBuffer.CurrentSnapshot,
hostDocument.CursorPosition.Value,
CancellationToken.None,
description,
span))
Assert.Equal(expectedDescription, description)
Assert.Equal(hostDocument.SelectedSpans.Single(), span)
End Using
End Sub
End Class
......@@ -334,6 +334,7 @@
<Compile Include="GoToDefinition\GoToDefinitionApiTests.vb" />
<Compile Include="GoToDefinition\MockNavigableItemsPresenter.vb" />
<Compile Include="Help\HelpTests.vb" />
<Compile Include="LanguageBlockTests.vb" />
<Compile Include="MockComponentModel.vb" />
<Compile Include="ObjectBrowser\AbstractObjectBrowserTests.vb" />
<Compile Include="ObjectBrowser\CSharp\ObjectBrowerTests.vb" />
......
......@@ -703,7 +703,7 @@ public bool IsIndexerMemberCRef(SyntaxNode node)
return node.Kind() == SyntaxKind.IndexerMemberCref;
}
public SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position)
public SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position, bool useFullSpan = true)
{
Contract.ThrowIfNull(root, "root");
Contract.ThrowIfTrue(position < 0 || position > root.FullSpan.End, "position");
......@@ -721,9 +721,12 @@ public SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position)
var node = root.FindToken(position).Parent;
while (node != null)
{
if (node is MemberDeclarationSyntax)
if (useFullSpan || node.Span.Contains(position))
{
return node;
if (node is MemberDeclarationSyntax)
{
return node;
}
}
node = node.Parent;
......
......@@ -114,7 +114,7 @@ internal interface ISyntaxFactsService : ILanguageService
bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo);
SyntaxNode GetContainingTypeDeclaration(SyntaxNode root, int position);
SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position);
SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position, bool useFullSpan = true);
SyntaxNode GetContainingVariableDeclaratorOfFieldDeclaration(SyntaxNode node);
SyntaxToken FindTokenOnLeftOfPosition(SyntaxNode node, int position, bool includeSkipped = true, bool includeDirectives = false, bool includeDocumentationComments = false);
......
......@@ -578,7 +578,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return False
End Function
Public Function GetContainingMemberDeclaration(root As SyntaxNode, position As Integer) As SyntaxNode Implements ISyntaxFactsService.GetContainingMemberDeclaration
Public Function GetContainingMemberDeclaration(root As SyntaxNode, position As Integer, Optional useFullSpan As Boolean = True) As SyntaxNode Implements ISyntaxFactsService.GetContainingMemberDeclaration
Contract.ThrowIfNull(root, NameOf(root))
Contract.ThrowIfTrue(position < 0 OrElse position > root.FullSpan.End, NameOf(position))
......@@ -593,25 +593,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim node = root.FindToken(position).Parent
While node IsNot Nothing
If TypeOf node Is MethodBlockBaseSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
If useFullSpan OrElse node.Span.Contains(position) Then
If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
If TypeOf node Is MethodBlockBaseSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then
Return node
End If
If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
If TypeOf node Is PropertyBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse
TypeOf node Is EnumBlockSyntax OrElse
TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is EventBlockSyntax OrElse
TypeOf node Is FieldDeclarationSyntax Then
Return node
If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then
Return node
End If
If TypeOf node Is PropertyBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse
TypeOf node Is EnumBlockSyntax OrElse
TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is EventBlockSyntax OrElse
TypeOf node Is FieldDeclarationSyntax Then
Return node
End If
End If
node = node.Parent
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册