提交 362a5d01 编写于 作者: L lorcanmooney

Add namespace-name suggestions for VB

上级 d20421ec
......@@ -432,35 +432,90 @@ public async Task NamespaceName_Unqualified_ExcludesCurrentDeclaration()
await VerifyItemIsAbsentAsync(source, "NS");
}
// [WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
// [Fact, Trait(Traits.Feature, Traits.Features.Completion)]
// public async Task NamespaceName_Unqualified_IncompleteDeclaration()
// {
// var source = @"
//namespace A.B.C0 { }
//
//namespace A
//{
// namespace B
// {
// namespace C$$
//
// namespace C1.X { }
// }
//
// namespace B.C2.Y { }
//}
//
//namespace A.B.C3.Z { }";
//
// await VerifyItemIsAbsentAsync(source, "C0");
// await VerifyItemExistsAsync(source, "C1");
// await VerifyItemExistsAsync(source, "C2");
// await VerifyItemExistsAsync(source, "C3");
// await VerifyItemIsAbsentAsync(source, "X");
// await VerifyItemIsAbsentAsync(source, "Y");
// await VerifyItemIsAbsentAsync(source, "Z");
// }
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Unqualified_WithNested()
{
var source = @"
namespace A
{
namespace $$
{
namespace B { }
}
}";
await VerifyItemIsAbsentAsync(source, "A");
await VerifyItemIsAbsentAsync(source, "B");
}
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Unqualified_WithNestedAndMatchingPeer()
{
var source = @"
namespace A.B { }
namespace A
{
namespace $$
{
namespace B { }
}
}";
await VerifyItemIsAbsentAsync(source, "A");
await VerifyItemExistsAsync(source, "B");
}
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Unqualified_InnerCompletionPosition()
{
var source = @"namespace Sys$$tem { }";
await VerifyItemExistsAsync(source, "System");
await VerifyItemIsAbsentAsync(source, "Runtime");
}
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Unqualified_IncompleteDeclaration()
{
var source = @"
namespace A
{
namespace B
{
namespace $$
namespace C1 { }
}
namespace B.C2 { }
}
namespace A.B.C3 { }";
// Ideally, all the C* namespaces would be recommended but, because of how the parser
// recovers from the missing braces, they end up with the following qualified names...
//
// C1 => A.B.?.C1
// C2 => A.B.B.C2
// C3 => A.A.B.C3
//
// ...none of which are found by the current algorithm.
await VerifyItemIsAbsentAsync(source, "C1");
await VerifyItemIsAbsentAsync(source, "C2");
await VerifyItemIsAbsentAsync(source, "C3");
await VerifyItemIsAbsentAsync(source, "A");
// Because of the above, B does end up in the completion list
// since A.B.B appears to be a peer of the new declaration
await VerifyItemExistsAsync(source, "B");
}
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
......@@ -500,35 +555,83 @@ namespace B.$$
await VerifyItemExistsAsync(source, "C");
}
// [WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
// [Fact, Trait(Traits.Feature, Traits.Features.Completion)]
// public async Task NamespaceName_Qualified_IncompleteDeclaration()
// {
// var source = @"
//namespace A.B.C.D0 { }
//
//namespace A
//{
// namespace B
// {
// namespace C.D$$
//
// namespace C.D1.X { }
// }
//
// namespace B.C.D2.Y { }
//}
//
//namespace A.B.C.D3.Z { }";
//
// await VerifyItemIsAbsentAsync(source, "D0");
// await VerifyItemExistsAsync(source, "D1");
// await VerifyItemExistsAsync(source, "D2");
// await VerifyItemExistsAsync(source, "D3");
// await VerifyItemIsAbsentAsync(source, "X");
// await VerifyItemIsAbsentAsync(source, "Y");
// await VerifyItemIsAbsentAsync(source, "Z");
// }
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Qualified_WithNested()
{
var source = @"
namespace A.$$
{
namespace B { }
}
";
await VerifyItemIsAbsentAsync(source, "A");
await VerifyItemIsAbsentAsync(source, "B");
}
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Qualified_WithNestedAndMatchingPeer()
{
var source = @"
namespace A.B { }
namespace A.$$
{
namespace B { }
}
";
await VerifyItemIsAbsentAsync(source, "A");
await VerifyItemExistsAsync(source, "B");
}
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Qualified_InnerCompletionPosition()
{
var source = @"namespace Sys$$tem.Runtime { }";
await VerifyItemExistsAsync(source, "System");
await VerifyItemIsAbsentAsync(source, "Runtime");
}
[WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NamespaceName_Qualified_IncompleteDeclaration()
{
var source = @"
namespace A
{
namespace B
{
namespace C.$$
namespace C.D1 { }
}
namespace B.C.D2 { }
}
namespace A.B.C.D3 { }";
await VerifyItemIsAbsentAsync(source, "A");
await VerifyItemIsAbsentAsync(source, "B");
await VerifyItemIsAbsentAsync(source, "C");
// Ideally, all the D* namespaces would be recommended but, because of how the parser
// recovers from the missing braces, they end up with the following qualified names...
//
// D1 => A.B.C.C.?.D1
// D2 => A.B.B.C.D2
// D3 => A.A.B.C.D3
//
// ...none of which are found by the current algorithm.
await VerifyItemIsAbsentAsync(source, "D1");
await VerifyItemIsAbsentAsync(source, "D2");
await VerifyItemIsAbsentAsync(source, "D3");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task UnderNamespace()
......
......@@ -108,7 +108,7 @@ private async Task CheckResultsAsync(Document document, int position, string exp
var completionService = GetCompletionService(document.Project.Solution.Workspace);
var completionList = await GetCompletionListAsync(completionService, document, position, trigger);
var items = completionList == null ? default(ImmutableArray<CompletionItem>) : completionList.Items;
var items = completionList == null ? ImmutableArray<CompletionItem>.Empty : completionList.Items;
if (checkForAbsence)
{
......
......@@ -303,6 +303,26 @@ End Class
Await VerifyBuilderAsync(markup, CompletionTrigger.Default, useDebuggerOptions:=True)
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceDeclarationName_Unqualified() As Task
Dim markup = <a>
Namespace $$
End Class
</a>
Await VerifyBuilderAsync(markup, CompletionTrigger.Default)
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceDeclarationName_Qualified() As Task
Dim markup = <a>
Namespace A.$$
End Class
</a>
Await VerifyBuilderAsync(markup, CompletionTrigger.Default)
End Function
Private Function VerifyNotBuilderAsync(markup As XElement, Optional triggerInfo As CompletionTrigger? = Nothing, Optional useDebuggerOptions As Boolean = False) As Task
Return VerifySuggestionModeWorkerAsync(markup, isBuilder:=False, triggerInfo:=triggerInfo, useDebuggerOptions:=useDebuggerOptions)
End Function
......
......@@ -5747,6 +5747,317 @@ End Module
Await VerifyItemExistsAsync(text, "D")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_TopLevelNoPeers() As Task
Dim source = <code><![CDATA[
Imports System;
Namespace $$
]]></code>.Value
Await VerifyItemExistsAsync(source, "System")
Await VerifyItemIsAbsentAsync(source, "String")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_TopLevelWithPeer() As Task
Dim source = <code><![CDATA[
Namespace A
End Namespace
Namespace $$
]]></code>.Value
Await VerifyItemExistsAsync(source, "A")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_NestedWithNoPeers() As Task
Dim source = <code><![CDATA[
Namespace A
Namespace $$
End Namespace
]]></code>.Value
Await VerifyNoItemsExistAsync(source)
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_NestedWithPeer() As Task
Dim source = <code><![CDATA[
Namespace A
Namespace B
End Namespace
Namespace $$
End Namespace
]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "A")
Await VerifyItemExistsAsync(source, "B")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_ExcludesCurrentDeclaration() As Task
Dim source = <code><![CDATA[Namespace N$$S]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "NS")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_WithNested() As Task
Dim source = <code><![CDATA[
Namespace A
Namespace $$
Namespace B
End Namespace
End Namespace
End Namespace
]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "A")
Await VerifyItemIsAbsentAsync(source, "B")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_WithNestedAndMatchingPeer() As Task
Dim source = <code><![CDATA[
Namespace A.B
End Namespace
Namespace A
Namespace $$
Namespace B
End Namespace
End Namespace
End Namespace
]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "A")
Await VerifyItemExistsAsync(source, "B")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_InnerCompletionPosition() As Task
Dim source = <code><![CDATA[
Namespace Sys$$tem
End Namespace
]]></code>.Value
Await VerifyItemExistsAsync(source, "System")
Await VerifyItemIsAbsentAsync(source, "Runtime")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Unqualified_IncompleteDeclaration() As Task
Dim source = <code><![CDATA[
Namespace A
Namespace B
Namespace $$
Namespace C1
End Namespace
End Namespace
Namespace B.C2
End Namespace
End Namespace
Namespace A.B.C3
End Namespace
]]></code>.Value
' Ideally, all the C* namespaces would be recommended but, because of how the parser
' recovers from the missing end statement, they end up with the following qualified names...
'
' C1 => A.B.?.C1
' C2 => A.B.B.C2
' C3 => A.A.B.C3
'
' ...none of which are found by the current algorithm.
Await VerifyItemIsAbsentAsync(source, "C1")
Await VerifyItemIsAbsentAsync(source, "C2")
Await VerifyItemIsAbsentAsync(source, "C3")
Await VerifyItemIsAbsentAsync(source, "A")
' Because of the above, B does end up in the completion list
' since A.B.B appears to be a peer of the New declaration
Await VerifyItemExistsAsync(source, "B")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Qualified_NoPeers() As Task
Dim source = <code><![CDATA[Namespace A.$$]]></code>.Value
Await VerifyNoItemsExistAsync(source)
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Qualified_TopLevelWithPeer() As Task
Dim source = <code><![CDATA[
Namespace A.B
End Namespace
Namespace A.$$
]]></code>.Value
Await VerifyItemExistsAsync(source, "B")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Qualified_NestedWithPeer() As Task
Dim source = <code><![CDATA[
Namespace A
Namespace B.C
End Namespace
Namespace B.$$
End Namespace
]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "A")
Await VerifyItemIsAbsentAsync(source, "B")
Await VerifyItemExistsAsync(source, "C")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Qualified_WithNested() As Task
Dim source = <code><![CDATA[
Namespace A.$$
Namespace B
End Namespace
End Namespace
]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "A")
Await VerifyItemIsAbsentAsync(source, "B")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Qualified_WithNestedAndMatchingPeer() As Task
Dim source = <code><![CDATA[
Namespace A.B
End Namespace
Namespace A.$$
Namespace B
End Namespace
End Namespace
]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "A")
Await VerifyItemExistsAsync(source, "B")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Qualified_InnerCompletionPosition() As Task
Dim source = <code><![CDATA[
Namespace Sys$$tem.Runtim
End Namespace
]]></code>.Value
Await VerifyItemExistsAsync(source, "System")
Await VerifyItemIsAbsentAsync(source, "Runtime")
End Function
<WorkItem(7213, "https://github.com/dotnet/roslyn/issues/7213")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function NamespaceName_Qualified_IncompleteDeclaration() As Task
Dim source = <code><![CDATA[
Namespace A
Namespace B
Namespace C.$$
Namespace C.D1
End Namespace
End Namespace
Namespace B.C.D2
End Namespace
End Namespace
Namespace A.B.C.D3
End Namespace
]]></code>.Value
Await VerifyItemIsAbsentAsync(source, "A")
Await VerifyItemIsAbsentAsync(source, "B")
Await VerifyItemIsAbsentAsync(source, "C")
' Ideally, all the D* namespaces would be recommended but, because of how the parser
' recovers from the end statement, they end up with the following qualified names...
'
' D1 => A.B.C.C.?.D1
' D2 => A.B.B.C.D2
' D3 => A.A.B.C.D3
'
' ...none of which are found by the current algorithm.
Await VerifyItemIsAbsentAsync(source, "D1")
Await VerifyItemIsAbsentAsync(source, "D2")
Await VerifyItemIsAbsentAsync(source, "D3")
End Function
<WorkItem(925469, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/925469")>
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function CommitWithCloseBracketLeaveOpeningBracket1() As Task
......
......@@ -79,6 +79,15 @@ internal class CSharpFeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Autoselect disabled due to namespace declaration..
/// </summary>
internal static string AutoselectDisabledDueToNamespaceDeclaration {
get {
return ResourceManager.GetString("AutoselectDisabledDueToNamespaceDeclaration", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Autoselect disabled due to possible explicitly named anonymous type member creation..
/// </summary>
......@@ -565,6 +574,15 @@ internal class CSharpFeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to &lt;namespace name&gt;.
/// </summary>
internal static string NamespaceName {
get {
return ResourceManager.GetString("NamespaceName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No common root node for extraction..
/// </summary>
......
......@@ -455,4 +455,10 @@
<data name="UseImplicitTypeDiagnosticTitle" xml:space="preserve">
<value>Use implicit type</value>
</data>
<data name="AutoselectDisabledDueToNamespaceDeclaration" xml:space="preserve">
<value>Autoselect disabled due to namespace declaration.</value>
</data>
<data name="NamespaceName" xml:space="preserve">
<value>&lt;namespace name&gt;</value>
</data>
</root>
\ No newline at end of file
......@@ -61,7 +61,7 @@ protected override async Task<CompletionItem> GetSuggestionModeItemAsync(Documen
}
else if (tree.IsNamespaceDeclarationNameContext(position, cancellationToken))
{
return CreateEmptySuggestionModeItem(itemSpan);
return CreateSuggestionModeItem(CSharpFeaturesResources.NamespaceName, itemSpan, CSharpFeaturesResources.AutoselectDisabledDueToNamespaceDeclaration);
}
}
......
......@@ -5,7 +5,6 @@ Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.Completion.SuggestionMode
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
......@@ -94,6 +93,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.SuggestionMode
Return CreateSuggestionModeItem(VBFeaturesResources.NewResource, itemSpan, description)
End If
' Builder at Namespace declaration name
If syntaxTree.IsNamespaceDeclarationNameContext(position, cancellationToken) Then
description = VBFeaturesResources.TypeANameHereToDeclareANamespace & vbCrLf &
VBFeaturesResources.NoteSpaceAndCompletion
Return CreateSuggestionModeItem(VBFeaturesResources.NamespaceName, itemSpan, description)
End If
Return Nothing
End Function
......
......@@ -1865,6 +1865,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources
End Get
End Property
'''<summary>
''' Looks up a localized string similar to &lt;namespace name&gt;.
'''</summary>
Friend ReadOnly Property NamespaceName() As String
Get
Return ResourceManager.GetString("NamespaceName", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Indicates that a conversion operator (CType) converts a class or structure to a type that might not be able to hold some of the possible values of the original class or structure..
'''</summary>
......@@ -2913,6 +2922,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Type a name here to declare a namespace..
'''</summary>
Friend ReadOnly Property TypeANameHereToDeclareANamespace() As String
Get
Return ResourceManager.GetString("TypeANameHereToDeclareANamespace", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Type a new name for the column, followed by &apos;=&apos;. Otherwise, the original column name with be used..
'''</summary>
......
......@@ -1204,4 +1204,10 @@ Sub(&lt;parameterList&gt;) &lt;statement&gt;</value>
<data name="Properties" xml:space="preserve">
<value>Properties</value>
</data>
<data name="NamespaceName" xml:space="preserve">
<value>&lt;namespace name&gt;</value>
</data>
<data name="TypeANameHereToDeclareANamespace" xml:space="preserve">
<value>Type a name here to declare a namespace.</value>
</data>
</root>
\ No newline at end of file
......@@ -27,7 +27,6 @@ internal sealed class CSharpSyntaxContext : AbstractSyntaxContext
public readonly bool IsLabelContext;
public readonly bool IsTypeArgumentOfConstraintContext;
public readonly bool IsNamespaceDeclarationNameContext;
public readonly bool IsIsOrAsContext;
public readonly bool IsObjectCreationTypeContext;
public readonly bool IsDefiniteCastTypeContext;
......@@ -63,6 +62,7 @@ internal sealed class CSharpSyntaxContext : AbstractSyntaxContext
bool isPreProcessorExpressionContext,
bool isTypeContext,
bool isNamespaceContext,
bool isNamespaceDeclarationNameContext,
bool isStatementContext,
bool isGlobalStatementContext,
bool isAnyExpressionContext,
......@@ -75,7 +75,6 @@ internal sealed class CSharpSyntaxContext : AbstractSyntaxContext
bool isInImportsDirective,
bool isLabelContext,
bool isTypeArgumentOfConstraintContext,
bool isNamespaceDeclarationNameContext,
bool isRightOfDotOrArrowOrColonColon,
bool isIsOrAsContext,
bool isObjectCreationTypeContext,
......@@ -98,7 +97,7 @@ internal sealed class CSharpSyntaxContext : AbstractSyntaxContext
bool isCatchFilterContext,
bool isDestructorTypeContext)
: base(workspace, semanticModel, position, leftToken, targetToken,
isTypeContext, isNamespaceContext,
isTypeContext, isNamespaceContext, isNamespaceDeclarationNameContext,
isPreProcessorDirectiveContext,
isRightOfDotOrArrowOrColonColon, isStatementContext, isAnyExpressionContext,
isAttributeNameContext, isEnumTypeMemberAccessContext, isNameOfContext,
......@@ -114,7 +113,6 @@ internal sealed class CSharpSyntaxContext : AbstractSyntaxContext
this.IsConstantExpressionContext = isConstantExpressionContext;
this.IsLabelContext = isLabelContext;
this.IsTypeArgumentOfConstraintContext = isTypeArgumentOfConstraintContext;
this.IsNamespaceDeclarationNameContext = isNamespaceDeclarationNameContext;
this.IsIsOrAsContext = isIsOrAsContext;
this.IsObjectCreationTypeContext = isObjectCreationTypeContext;
this.IsDefiniteCastTypeContext = isDefiniteCastTypeContext;
......@@ -201,6 +199,7 @@ public static CSharpSyntaxContext CreateContext(Workspace workspace, SemanticMod
isPreProcessorExpressionContext,
syntaxTree.IsTypeContext(position, cancellationToken, semanticModelOpt: semanticModel),
syntaxTree.IsNamespaceContext(position, cancellationToken, semanticModelOpt: semanticModel),
syntaxTree.IsNamespaceDeclarationNameContext(position, cancellationToken),
isStatementContext,
isGlobalStatementContext,
isAnyExpressionContext,
......@@ -213,7 +212,6 @@ public static CSharpSyntaxContext CreateContext(Workspace workspace, SemanticMod
IsLeftSideOfUsingAliasDirective(leftToken, cancellationToken),
syntaxTree.IsLabelContext(position, cancellationToken),
syntaxTree.IsTypeArgumentOfConstraintClause(position, cancellationToken),
syntaxTree.IsNamespaceDeclarationNameContext(position, cancellationToken),
syntaxTree.IsRightOfDotOrArrowOrColonColon(position, cancellationToken),
syntaxTree.IsIsOrAsContext(position, leftToken, cancellationToken),
syntaxTree.IsObjectCreationTypeContext(position, leftToken, cancellationToken),
......
......@@ -603,6 +603,18 @@ public static bool IsAttributeNameContext(this SyntaxTree syntaxTree, int positi
return syntaxTree.IsTypeContext(position, cancellationToken, semanticModelOpt);
}
public static bool IsNamespaceDeclarationNameContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);
var namespaceDeclaration = token.GetAncestor<NamespaceDeclarationSyntax>();
if (namespaceDeclaration == null)
{
return false;
}
return namespaceDeclaration.Name.Span.IntersectsWith(position) || token == namespaceDeclaration.NamespaceKeyword;
}
public static bool IsDefinitelyNotTypeContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
return
......
......@@ -111,18 +111,6 @@ private static bool BaseTypeDeclarationContainsPosition(BaseTypeDeclarationSynta
private static readonly Func<SyntaxKind, bool> s_isDotOrArrowOrColonColon =
k => k == SyntaxKind.DotToken || k == SyntaxKind.MinusGreaterThanToken || k == SyntaxKind.ColonColonToken;
public static bool IsNamespaceDeclarationNameContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);
var namespaceDeclaration = token.GetAncestor<NamespaceDeclarationSyntax>();
if (namespaceDeclaration == null)
{
return false;
}
return namespaceDeclaration.Name.Span.IntersectsWith(position) || token == namespaceDeclaration.NamespaceKeyword;
}
public static bool IsRightOfDotOrArrowOrColonColon(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
return syntaxTree.IsRightOf(position, s_isDotOrArrowOrColonColon, cancellationToken);
......
......@@ -80,7 +80,7 @@ internal class CSharpRecommendationService : AbstractRecommendationService
}
else if (context.IsTypeContext || context.IsNamespaceContext)
{
return GetSymbolsForTypeOrNamespaceContext(context, cancellationToken);
return GetSymbolsForTypeOrNamespaceContext(context);
}
else if (context.IsLabelContext)
{
......@@ -217,9 +217,7 @@ internal class CSharpRecommendationService : AbstractRecommendationService
.AsImmutableOrEmpty();
}
private static IEnumerable<ISymbol> GetSymbolsForTypeOrNamespaceContext(
CSharpSyntaxContext context,
CancellationToken cancellationToken)
private static IEnumerable<ISymbol> GetSymbolsForTypeOrNamespaceContext(CSharpSyntaxContext context)
{
var symbols = context.SemanticModel.LookupNamespacesAndTypes(context.LeftToken.SpanStart);
......@@ -236,20 +234,10 @@ internal class CSharpRecommendationService : AbstractRecommendationService
return symbols;
}
private static IEnumerable<ISymbol> GetSymbolsForNamespaceDeclarationNameContext(
CSharpSyntaxContext context,
CancellationToken cancellationToken)
private static IEnumerable<ISymbol> GetSymbolsForNamespaceDeclarationNameContext(CSharpSyntaxContext context, CancellationToken cancellationToken)
{
var namespaceDeclaration = context.TargetToken.GetAncestor<NamespaceDeclarationSyntax>();
var declaredNamespaceSymbol = context.SemanticModel.GetDeclaredSymbol(namespaceDeclaration);
var containingNamespaceSymbol = context.SemanticModel.Compilation.GetCompilationNamespace(declaredNamespaceSymbol.ContainingNamespace);
var symbols = context.SemanticModel
.LookupNamespacesAndTypes(context.LeftToken.SpanStart, containingNamespaceSymbol)
.Where(symbol => IsNonIntersectingNamespace(symbol, context));
return symbols;
var declarationSyntax = context.TargetToken.GetAncestor<NamespaceDeclarationSyntax>();
return GetRecommendedNamespaceNameSymbols(context.SemanticModel, declarationSyntax, cancellationToken);
}
private static IEnumerable<ISymbol> GetSymbolsForExpressionOrStatementContext(
......@@ -337,7 +325,8 @@ internal class CSharpRecommendationService : AbstractRecommendationService
if (context.IsNamespaceDeclarationNameContext)
{
return symbols.Where(s => IsNonIntersectingNamespace(s, context));
NamespaceDeclarationSyntax declarationSyntax = name.GetAncestorOrThis<NamespaceDeclarationSyntax>();
return symbols.Where(s => IsNonIntersectingNamespace(s, declarationSyntax));
}
// Filter the types when in a using directive, but not an alias.
......@@ -369,11 +358,6 @@ internal class CSharpRecommendationService : AbstractRecommendationService
return SpecializedCollections.EmptyEnumerable<ISymbol>();
}
private static bool IsNonIntersectingNamespace(ISymbol symbol, CSharpSyntaxContext context)
{
return symbol.IsNamespace() && symbol.Locations.Any(location => !context.IntersectsWith(location));
}
private static IEnumerable<ISymbol> GetSymbolsOffOfExpression(
CSharpSyntaxContext context,
ExpressionSyntax originalExpression,
......
......@@ -29,6 +29,26 @@ internal abstract class AbstractRecommendationService : IRecommendationService
return symbols;
}
protected static IEnumerable<ISymbol> GetRecommendedNamespaceNameSymbols(
SemanticModel semanticModel, SyntaxNode declarationSyntax, CancellationToken cancellationToken)
{
var containingNamespaceSymbol = semanticModel.Compilation.GetCompilationNamespace(
semanticModel.GetEnclosingNamespace(declarationSyntax.SpanStart, cancellationToken));
var symbols = semanticModel.LookupNamespacesAndTypes(declarationSyntax.SpanStart, containingNamespaceSymbol)
.Where(recommendationSymbol => IsNonIntersectingNamespace(recommendationSymbol, declarationSyntax));
return symbols;
}
protected static bool IsNonIntersectingNamespace(ISymbol recommendationSymbol, SyntaxNode declarationSyntax)
{
return recommendationSymbol.IsNamespace() &&
recommendationSymbol.Locations.Any(
candidateLocation => !(declarationSyntax.SyntaxTree == candidateLocation.SourceTree &&
declarationSyntax.Span.IntersectsWith(candidateLocation.SourceSpan)));
}
private sealed class ShouldIncludeSymbolContext
{
private readonly AbstractSyntaxContext _context;
......
// 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.Collections.Generic;
using System.Threading;
using Microsoft.CodeAnalysis.Host;
......@@ -20,6 +19,7 @@ internal abstract class AbstractSyntaxContext
SyntaxToken targetToken,
bool isTypeContext,
bool isNamespaceContext,
bool isNamespaceDeclarationNameContext,
bool isPreProcessorDirectiveContext,
bool isRightOfNameSeparator,
bool isStatementContext,
......@@ -38,6 +38,7 @@ internal abstract class AbstractSyntaxContext
this.TargetToken = targetToken;
this.IsTypeContext = isTypeContext;
this.IsNamespaceContext = isNamespaceContext;
this.IsNamespaceDeclarationNameContext = isNamespaceDeclarationNameContext;
this.IsPreProcessorDirectiveContext = isPreProcessorDirectiveContext;
this.IsRightOfNameSeparator = isRightOfNameSeparator;
this.IsStatementContext = isStatementContext;
......@@ -60,6 +61,8 @@ internal abstract class AbstractSyntaxContext
public bool IsTypeContext { get; }
public bool IsNamespaceContext { get; }
public bool IsNamespaceDeclarationNameContext { get; }
public bool IsPreProcessorDirectiveContext { get; }
public bool IsRightOfNameSeparator { get; }
......@@ -106,15 +109,5 @@ public ISet<INamedTypeSymbol> GetOuterTypes(CancellationToken cancellationToken)
{
return this.Workspace.Services.GetService<TService>();
}
public bool IntersectsWith(Location location)
{
if (location == null)
{
throw new ArgumentNullException(nameof(location));
}
return location.SourceTree == SyntaxTree && location.SourceSpan.IntersectsWith(Position);
}
}
}
......@@ -60,6 +60,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
Return syntaxTree.IsTypeContext(position, token, cancellationToken, semanticModelOpt)
End Function
<Extension()>
Public Function IsNamespaceDeclarationNameContext(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean
Dim statement = syntaxTree.GetTargetToken(position, cancellationToken).GetAncestor(Of NamespaceStatementSyntax)
Return statement IsNot Nothing AndAlso statement.Name.Span.IntersectsWith(position)
End Function
<Extension()>
Public Function GetContainingTypeBlock(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As TypeBlockSyntax
Dim token = syntaxTree.GetRoot(cancellationToken).FindToken(position)
......
......@@ -61,6 +61,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
touchingToken As SyntaxToken,
isTypeContext As Boolean,
isNamespaceContext As Boolean,
isNamespaceDeclarationNameContext As Boolean,
isPreProcessorDirectiveContext As Boolean,
isRightOfNameSeparator As Boolean,
isSingleLineStatementContext As Boolean,
......@@ -83,6 +84,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
targetToken,
isTypeContext,
isNamespaceContext,
isNamespaceDeclarationNameContext,
isPreProcessorDirectiveContext,
isRightOfNameSeparator,
isStatementContext:=isSingleLineStatementContext,
......@@ -141,6 +143,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
touchingToken,
isTypeContext:=syntaxTree.IsTypeContext(position, targetToken, cancellationToken, semanticModel),
isNamespaceContext:=syntaxTree.IsNamespaceContext(position, targetToken, cancellationToken, semanticModel),
isNamespaceDeclarationNameContext:=syntaxTree.IsNamespaceDeclarationNameContext(position, cancellationToken),
isPreProcessorDirectiveContext:=syntaxTree.IsInPreprocessorDirectiveContext(position, cancellationToken),
isRightOfNameSeparator:=syntaxTree.IsRightOfDot(position, cancellationToken),
isSingleLineStatementContext:=syntaxTree.IsSingleLineStatementContext(position, targetToken, cancellationToken),
......
......@@ -245,10 +245,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Function
Public Function IsNamespaceDeclarationNameContext(semanticModel As SemanticModel, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISemanticFactsService.IsNamespaceDeclarationNameContext
'
' TODO: part of https://github.com/dotnet/roslyn/issues/7213
'
Return False
Return semanticModel.SyntaxTree.IsNamespaceDeclarationNameContext(position, cancellationToken)
End Function
End Class
End Namespace
......@@ -4,7 +4,6 @@ Imports System.Collections.Immutable
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Recommendations
Imports Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery
......@@ -72,11 +71,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
Dim symbols = GetUnqualifiedSymbolsForExpressionOrStatementContext(context, filterOutOfScopeLocals, cancellationToken) _
.Where(AddressOf IsWritableFieldOrLocal)
Return symbols
ElseIf context.IsNamespaceDeclarationNameContext Then
Return GetUnqualifiedSymbolsForNamespaceDeclarationNameContext(context, cancellationToken)
End If
Return SpecializedCollections.EmptyEnumerable(Of ISymbol)()
End Function
Private Function GetUnqualifiedSymbolsForNamespaceDeclarationNameContext(context As VisualBasicSyntaxContext, cancellationToken As CancellationToken) As IEnumerable(Of ISymbol)
Dim declarationSyntax = context.TargetToken.GetAncestor(Of NamespaceBlockSyntax)
Return GetRecommendedNamespaceNameSymbols(context.SemanticModel, declarationSyntax, cancellationToken)
End Function
Private Function IsWritableFieldOrLocal(symbol As ISymbol) As Boolean
If symbol.Kind() = SymbolKind.Field Then
Dim field = DirectCast(symbol, IFieldSymbol)
......@@ -170,7 +176,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
symbols = symbols.Where(Function(s) Not IsInEligibleDelegate(s))
End If
' Hide backing fields and events
Return symbols.Where(Function(s) FilterEventsAndGeneratedSymbols(Nothing, s))
End Function
......@@ -190,11 +195,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
cancellationToken As CancellationToken
) As IEnumerable(Of ISymbol)
' We shouldn't show completion if we're inside of a namespace statement.
If context.TargetToken.Parent.FirstAncestorOrSelf(Of NamespaceStatementSyntax)() IsNot Nothing Then
Return SpecializedCollections.EmptyEnumerable(Of ISymbol)()
End If
' We're in a name-only context, since if we were an expression we'd be a
' MemberAccessExpressionSyntax. Thus, let's do other namespaces and types.
Dim leftHandSymbolInfo = context.SemanticModel.GetSymbolInfo(node.Left, cancellationToken)
......@@ -212,6 +212,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Recommendations
Else
symbols = context.SemanticModel _
.LookupNamespacesAndTypes(position:=node.SpanStart, container:=leftHandSymbol)
If context.IsNamespaceDeclarationNameContext Then
Dim declarationSyntax = node.GetAncestor(Of NamespaceBlockSyntax)
symbols = symbols.Where(Function(symbol) IsNonIntersectingNamespace(symbol, declarationSyntax))
End If
End If
Return FilterToValidAccessibleSymbols(symbols, context, cancellationToken)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册