提交 b3cbce15 编写于 作者: L lorcanmooney 提交者: Sam Harwell

XML-doc commit test parity

上级 a62b2cab
......@@ -507,6 +507,23 @@ public async Task TypeParamNames()
{
var text = @"
public class Outer<TOuter>
{
public class Inner<TInner>
{
/// <typeparam name=""$$""/>
public int Method<TMethod>(T green) { }
}
}";
await VerifyItemsExistAsync(text, "TMethod");
await VerifyItemsAbsentAsync(text, "TOuter", "TInner");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TypeParamNamesInWrongScope()
{
var text = @"
public class Outer<TOuter>
{
public class Inner<TInner>
{
......@@ -529,9 +546,7 @@ public class Outer<TOuter>
{
public class Inner<TInner>
{
/// <summary>
/// <typeparam name=""T$$""/>
/// </summary>
public int Method<TMethod>(T green) { }
}
}";
......@@ -593,11 +608,24 @@ static void Goo(string str)
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task ListTypes()
public async Task ListAttributes()
{
await VerifyItemsExistAsync(@"
/// <summary>
/// <list $$></list>
/// </summary>
static void Goo()
{
}
", "type");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task ListTypeValues()
{
await VerifyItemsExistAsync(@"
/// <summary>
/// <list type=""$$""
/// <list type=""$$""></list>
/// </summary>
static void Goo()
{
......@@ -605,13 +633,27 @@ static void Goo()
", "bullet", "number", "table");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11490")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task SeeAttributeNames()
{
await VerifyItemsExistAsync(@"
/// <summary>
/// <see $$/>
/// </summary>
static void Goo()
{
}
", "cref", "langword");
}
[WorkItem(11490, "https://github.com/dotnet/roslyn/issues/11490")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task SeeLangwordValues()
{
await VerifyItemsExistAsync(@"
/// <summary>
/// <see langword=""$$""
/// <see langword=""$$""/>
/// </summary>
static void Goo()
{
......@@ -621,7 +663,7 @@ static void Goo()
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task SeeAttributesOnSpace()
public async Task AttributeNamesOnSpaceAfterTagName()
{
var text = @"
/// <summary>
......@@ -635,55 +677,124 @@ static void Goo()
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task SeeLangwordValuesOnQuote()
public async Task AttributeNamesAfterTagNameWithinIncompleteElement()
{
var text = @"
/// <summary>
/// <see langword=""$$
/// </summary>
static void Goo()
class C
{
}";
await VerifyItemExistsAsync(text, "await", usePreviousCharAsTrigger: true);
/// <see $$
void Goo() { }
}
";
await VerifyItemExistsAsync(text, "cref");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task AttributeNameAfterElementName()
public async Task AttributeNamesAfterTagNameInEmptyElement()
{
var text = @"
class C
{
/// <exception $$
/// <see $$/>
void Goo() { }
}
";
await VerifyItemExistsAsync(text, "cref");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task PartiallyTypedAttributeName()
public async Task AttributeNamesAfterTagNameInElementStartTag()
{
var text = @"
class C
{
/// <exception c$$
/// <summary>
/// <see $$>
/// </summary>
void Goo() { }
}
";
await VerifyItemExistsAsync(text, "langword");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task AttributeNamesAfterPartiallyTypedAttributeName()
{
var text = @"
class C
{
/// <summary>
/// <see c$$
/// </summary>
void Goo() { }
}
";
await VerifyItemExistsAsync(text, "cref");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task AttributeNamesAfterNameAttribute()
{
var text = @"
class C
{
/// <summary>
/// <see name="""" $$
/// </summary>
void Goo() { }
}
";
await VerifyItemExistsAsync(text, "cref");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task AttributeNamesAfterCrefAttribute()
{
var text = @"
class C
{
/// <summary>
/// <see cref="""" $$
/// </summary>
void Goo() { }
}
";
await VerifyItemExistsAsync(text, "langword");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task AttributeNameAfterAttribute()
public async Task AttributeNamesAfterTextAttribute()
{
var text = @"
class C
{
/// <exception name="""" $$
/// <summary>
/// <see goo="""" $$
/// </summary>
void Goo() { }
}
";
await VerifyItemExistsAsync(text, "cref");
}
[WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11489")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task AttributeValuesOnQuote()
{
var text = @"
/// <summary>
/// <see langword=""$$
/// </summary>
static void Goo()
{
}";
await VerifyItemExistsAsync(text, "await", usePreviousCharAsTrigger: true);
}
}
}
......@@ -584,7 +584,9 @@ class c
<Document><![CDATA[
class c
{
/// <summary>
/// $$
/// </summary>
void goo() { }
}
]]></Document>)
......@@ -653,6 +655,30 @@ class c
End Using
End Function
<WorkItem(623219, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/623219")>
<WorkItem(746919, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/746919")>
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function CommitParam() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
class c<T>
{
/// <param$$
void goo<T>(T bar) { }
}
]]></Document>)
state.SendInvokeCompletionList()
Await state.AssertCompletionSession()
Await state.AssertSelectedCompletionItem(displayText:="param name=""bar""")
state.SendReturn()
Await state.AssertNoCompletionSession()
' /// <param name="bar"$$
Await state.AssertLineTextAroundCaret(" /// <param name=""bar""", "")
End Using
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function CommitParamNoOpenAngle() As Task
......@@ -1070,5 +1096,56 @@ class c<T>
End Using
End Function
<WorkItem(638653, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638653")>
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function AllowTypingDoubleQuote() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
class c
{
/// <param$$
void goo<T>(T bar) { }
}
]]></Document>)
state.SendInvokeCompletionList()
Await state.AssertCompletionSession()
Await state.AssertSelectedCompletionItem(displayText:="param name=""bar""")
state.SendTypeChars(" name=""")
' /// <param name="$$
Await state.AssertLineTextAroundCaret(" /// <param name=""", "")
' Because the item contains a double quote, the completion list should still be present with the same selection
Await state.AssertCompletionSession()
Await state.AssertSelectedCompletionItem(displayText:="param name=""bar""")
End Using
End Function
<WorkItem(638653, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638653")>
<WpfFact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function AllowTypingSpace() As Task
Using state = TestState.CreateCSharpTestState(
<Document><![CDATA[
class c
{
/// <param$$
void goo<T>(T bar) { }
}
]]></Document>)
state.SendInvokeCompletionList()
Await state.AssertCompletionSession()
Await state.AssertSelectedCompletionItem(displayText:="param name=""bar""")
state.SendTypeChars(" ")
' /// <param $$
Await state.AssertLineTextAroundCaret(" /// <param ", "")
' Because the item contains a space, the completion list should still be present with the same selection
Await state.AssertCompletionSession()
Await state.AssertSelectedCompletionItem(displayText:="param name=""bar""")
End Using
End Function
End Class
End Namespace
......@@ -20,6 +20,10 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
internal partial class XmlDocCommentCompletionProvider : AbstractDocCommentCompletionProvider<DocumentationCommentTriviaSyntax>
{
public XmlDocCommentCompletionProvider() : base(s_defaultRules)
{
}
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options)
{
var c = text[characterPosition];
......@@ -122,9 +126,7 @@ internal override bool IsInsertionTrigger(SourceText text, int characterPosition
if (token.Parent.Parent is DocumentationCommentTriviaSyntax ||
(token.Parent.Parent.IsKind(SyntaxKind.XmlEmptyElement) && token.Parent.Parent.Parent is DocumentationCommentTriviaSyntax))
{
items.AddRange(GetTopLevelSingleUseItems(parentTrivia));
items.AddRange(GetTopLevelRepeatableItems());
items.AddRange(GetItemsForSymbol(declaredSymbol, parentTrivia));
items.AddRange(GetTopLevelItems(declaredSymbol, parentTrivia));
}
}
......@@ -282,7 +284,7 @@ private bool IsAttributeValueContext(SyntaxToken token, out string tagName, out
SyntaxFacts.GetKeywordKinds().Select(SyntaxFacts.GetText);
protected override IEnumerable<string> GetExistingTopLevelElementNames(DocumentationCommentTriviaSyntax syntax) =>
syntax.Content.Select(GetElementName);
syntax.Content.Select(GetElementName).WhereNotNull();
protected override IEnumerable<string> GetExistingTopLevelAttributeValues(DocumentationCommentTriviaSyntax syntax, string elementName, string attributeName)
{
......@@ -328,22 +330,5 @@ private string GetAttributeValue(XmlAttributeSyntax attribute)
filterCharacterRules: FilterRules,
commitCharacterRules: ImmutableArray.Create(CharacterSetModificationRule.Create(CharacterSetModificationKind.Add, '>', '\t')),
enterKeyRule: EnterKeyRule.Never);
protected override CompletionItemRules GetCompletionItemRules(string displayText)
{
var commitRules = s_defaultRules.CommitCharacterRules;
if (displayText.Contains("\""))
{
commitRules = commitRules.Add(WithoutQuoteRule);
}
if (displayText.Contains(" "))
{
commitRules = commitRules.Add(WithoutSpaceRule);
}
return s_defaultRules.WithCommitCharacterRules(commitRules);
}
}
}
// 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.Collections.Immutable;
using System.Linq;
......@@ -58,6 +59,13 @@ internal abstract class AbstractDocCommentCompletionProvider<TSyntax> : CommonCo
private static readonly ImmutableArray<string> s_listTypeValues = ImmutableArray.Create("bullet", "number", "table");
private readonly CompletionItemRules defaultRules;
protected AbstractDocCommentCompletionProvider(CompletionItemRules defaultRules)
{
this.defaultRules = defaultRules ?? throw new ArgumentNullException(nameof(defaultRules)); ;
}
public override async Task ProvideCompletionsAsync(CompletionContext context)
{
if (!context.Options.GetOption(CompletionControllerOptions.ShowXmlDocCommentCompletion))
......@@ -80,9 +88,6 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
protected abstract IEnumerable<string> GetExistingTopLevelAttributeValues(TSyntax syntax, string tagName, string attributeName);
private bool HasExistingTopLevelElement(TSyntax syntax, string name) =>
GetExistingTopLevelElementNames(syntax).Contains(name);
private CompletionItem GetItem(string name)
{
if (s_tagMap.TryGetValue(name, out var values))
......@@ -184,36 +189,19 @@ protected IEnumerable<CompletionItem> GetAttributeValueItems(ISymbol symbol, str
return s_listTypeValues.Select(CreateCompletionItem);
}
return null;
return SpecializedCollections.EmptyEnumerable<CompletionItem>();
}
protected abstract IEnumerable<string> GetKeywordNames();
protected IEnumerable<CompletionItem> GetTopLevelRepeatableItems()
{
return s_topLevelRepeatableTagNames.Select(GetItem);
}
protected IEnumerable<CompletionItem> GetTopLevelSingleUseItems(TSyntax syntax)
{
var tagNames = new HashSet<string>(s_topLevelSingleUseTagNames);
tagNames.RemoveAll(GetExistingTopLevelElementNames(syntax).WhereNotNull());
return tagNames.Select(GetItem);
}
protected IEnumerable<CompletionItem> GetListItems()
protected IEnumerable<CompletionItem> GetTopLevelItems(ISymbol symbol, TSyntax syntax)
{
return s_listTagNames.Select(GetItem);
}
var items = new List<CompletionItem>();
protected IEnumerable<CompletionItem> GetListHeaderItems()
{
return s_listHeaderTagNames.Select(GetItem);
}
var existingTopLevelTags = new HashSet<string>(GetExistingTopLevelElementNames(syntax));
protected IEnumerable<CompletionItem> GetItemsForSymbol(ISymbol symbol, TSyntax syntax)
{
var items = new List<CompletionItem>();
items.AddRange(s_topLevelSingleUseTagNames.Except(existingTopLevelTags).Select(GetItem));
items.AddRange(s_topLevelRepeatableTagNames.Select(GetItem));
if (symbol != null)
{
......@@ -221,14 +209,14 @@ protected IEnumerable<CompletionItem> GetItemsForSymbol(ISymbol symbol, TSyntax
items.AddRange(GetParameterItems(symbol.GetTypeParameters(), syntax, TypeParameterElementName));
var property = symbol as IPropertySymbol;
if (property != null && !HasExistingTopLevelElement(syntax, ValueElementName))
if (property != null && !existingTopLevelTags.Contains(ValueElementName))
{
items.Add(GetItem(ValueElementName));
}
var method = symbol as IMethodSymbol;
var returns = method != null && !method.ReturnsVoid;
if (returns && !HasExistingTopLevelElement(syntax, ReturnsElementName))
if (returns && !existingTopLevelTags.Contains(ReturnsElementName))
{
items.Add(GetItem(ReturnsElementName));
}
......@@ -237,6 +225,16 @@ protected IEnumerable<CompletionItem> GetItemsForSymbol(ISymbol symbol, TSyntax
return items;
}
protected IEnumerable<CompletionItem> GetListItems()
{
return s_listTagNames.Select(GetItem);
}
protected IEnumerable<CompletionItem> GetListHeaderItems()
{
return s_listHeaderTagNames.Select(GetItem);
}
private IEnumerable<CompletionItem> GetParameterItems<TSymbol>(ImmutableArray<TSymbol> symbols, TSyntax syntax, string tagName) where TSymbol : ISymbol
{
var names = symbols.Select(p => p.Name).ToSet();
......@@ -311,12 +309,27 @@ private CompletionItem CreateCompletionItem(string displayText)
rules: GetCompletionItemRules(displayText));
}
internal static readonly CharacterSetModificationRule WithoutQuoteRule = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '"');
internal static readonly CharacterSetModificationRule WithoutSpaceRule = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, ' ');
private static readonly CharacterSetModificationRule WithoutQuoteRule = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, '"');
private static readonly CharacterSetModificationRule WithoutSpaceRule = CharacterSetModificationRule.Create(CharacterSetModificationKind.Remove, ' ');
internal static readonly ImmutableArray<CharacterSetModificationRule> FilterRules = ImmutableArray.Create(
CharacterSetModificationRule.Create(CharacterSetModificationKind.Add, '!', '-', '['));
protected abstract CompletionItemRules GetCompletionItemRules(string displayText);
private CompletionItemRules GetCompletionItemRules(string displayText)
{
var commitRules = defaultRules.CommitCharacterRules;
if (displayText.Contains("\""))
{
commitRules = commitRules.Add(WithoutQuoteRule);
}
if (displayText.Contains(" "))
{
commitRules = commitRules.Add(WithoutSpaceRule);
}
return defaultRules.WithCommitCharacterRules(commitRules);
}
}
}
......@@ -12,6 +12,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
Partial Friend Class XmlDocCommentCompletionProvider
Inherits AbstractDocCommentCompletionProvider(Of DocumentationCommentTriviaSyntax)
Public Sub New()
MyBase.New(s_defaultRules)
End Sub
Friend Overrides Function IsInsertionTrigger(text As SourceText, characterPosition As Integer, options As OptionSet) As Boolean
Dim isStartOfTag = text(characterPosition) = "<"c
Dim isClosingTag = (text(characterPosition) = "/"c AndAlso characterPosition > 0 AndAlso text(characterPosition - 1) = "<"c)
......@@ -102,11 +106,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
items.AddRange(GetAlwaysVisibleItems())
Dim parentElement = token.GetAncestor(Of XmlElementSyntax)()
If parentElement Is Nothing Then
Return items
End If
Dim grandParent = parentElement.Parent
Dim grandParent = parentElement?.Parent
If grandParent.IsKind(SyntaxKind.XmlElement) Then
items.AddRange(GetNestedItems(symbol))
......@@ -118,20 +118,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
If GetStartTagName(grandParent) = ListHeaderElementName Then
items.AddRange(GetListHeaderItems())
End If
ElseIf token.Parent.IsKind(SyntaxKind.XmlText) AndAlso token.Parent.Parent.IsKind(SyntaxKind.XmlElement) Then
items.AddRange(GetNestedItems(symbol))
If GetStartTagName(token.Parent.Parent) = ListElementName Then
items.AddRange(GetListItems())
End If
ElseIf token.Parent.IsKind(SyntaxKind.XmlText) Then
If token.Parent.IsParentKind(SyntaxKind.DocumentationCommentTrivia) Then
' Top level, without tag:
' ''' $$
items.AddRange(GetTopLevelItems(symbol, parent))
ElseIf token.Parent.IsParentKind(SyntaxKind.XmlElement) Then
items.AddRange(GetNestedItems(symbol))
If GetStartTagName(token.Parent.Parent) = ListElementName Then
items.AddRange(GetListItems())
End If
If GetStartTagName(token.Parent.Parent) = ListHeaderElementName Then
items.AddRange(GetListHeaderItems())
If GetStartTagName(token.Parent.Parent) = ListHeaderElementName Then
items.AddRange(GetListHeaderItems())
End If
End If
ElseIf grandParent.IsKind(SyntaxKind.DocumentationCommentTrivia) Then
items.AddRange(GetItemsForSymbol(symbol, parent))
items.AddRange(GetTopLevelSingleUseItems(parent))
items.AddRange(GetTopLevelRepeatableItems())
' Top level, with tag:
' ''' <$$
' ''' <tag$$
items.AddRange(GetTopLevelItems(symbol, parent))
End If
If token.Parent.IsKind(SyntaxKind.XmlElementStartTag, SyntaxKind.XmlName) Then
......@@ -241,7 +248,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
End Function
Protected Overrides Function GetExistingTopLevelElementNames(parentTrivia As DocumentationCommentTriviaSyntax) As IEnumerable(Of String)
Return parentTrivia.Content.Select(AddressOf GetElementName)
Return parentTrivia.Content.Select(AddressOf GetElementName).WhereNotNull()
End Function
Protected Overrides Function GetExistingTopLevelAttributeValues(syntax As DocumentationCommentTriviaSyntax, elementName As String, attributeName As String) As IEnumerable(Of String)
......@@ -310,19 +317,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
filterCharacterRules:=FilterRules,
enterKeyRule:=EnterKeyRule.Never)
Protected Overrides Function GetCompletionItemRules(displayText As String) As CompletionItemRules
Dim commitRules = s_defaultRules.CommitCharacterRules
If displayText.Contains("""") Then
commitRules = commitRules.Add(WithoutQuoteRule)
End If
If displayText.Contains(" ") Then
commitRules = commitRules.Add(WithoutSpaceRule)
End If
Return s_defaultRules.WithCommitCharacterRules(commitRules)
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册