Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not put an equals and quotes when completing an xml attribute if present #72508

Merged
merged 8 commits into from
Mar 21, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,35 @@ static void Goo()
""", "cref", "langword", "href");
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72259")]
public async Task SeeAttributeNames2()
{
var text = """
class C
{
/// <summary>
/// <see l$$=""/>
This conversation was marked as resolved.
Show resolved Hide resolved
/// </summary>
static void Goo()
{
}
}
""";
var expected = """
class C
{
/// <summary>
/// <see langword=""/>
This conversation was marked as resolved.
Show resolved Hide resolved
/// </summary>
static void Goo()
{
}
}
""";

await VerifyProviderCommitAsync(text, "langword", expected, null);
}
This conversation was marked as resolved.
Show resolved Hide resolved

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37504")]
public async Task SeeAlsoAttributeNames()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,76 @@ class c
End Using
End Function

<WpfTheory, CombinatorialData>
Public Async Function InvokeWithOpenAngleSeeCommitSeeWithEqualsQuotes(showCompletionInArgumentLists As Boolean) As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document><![CDATA[
class c
{
/// <summary>
/// <see $$=""
/// </summary>
void goo() { }
}
]]></Document>, showCompletionInArgumentLists:=showCompletionInArgumentLists)

This conversation was marked as resolved.
Show resolved Hide resolved
state.SendInvokeCompletionList()
state.AssertItemsInOrder({"!--", "![CDATA[", "inheritdoc", "see", "seealso"})
state.SendTypeChars("see")
Await state.AssertSelectedCompletionItem(displayText:="see")
state.SendReturn()

' /// <see <see cref=""/$$>=""
Await state.AssertLineTextAroundCaret(" /// <see <see cref=""""/", ">=""""")
End Using
End Function

<WpfTheory, CombinatorialData>
Public Async Function InvokeWithOpenAngleSeeCommitLangwordWithEqualsQuotes(showCompletionInArgumentLists As Boolean) As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document><![CDATA[
class c
{
/// <summary>
/// <see $$=""
/// </summary>
void goo() { }
}
]]></Document>, showCompletionInArgumentLists:=showCompletionInArgumentLists)

state.SendTypeChars("l")
state.SendInvokeCompletionList()
Await state.AssertSelectedCompletionItem(displayText:="langword")
state.SendReturn()

' /// <see langword="$$"
Await state.AssertLineTextAroundCaret(" /// <see langword=""", """")
End Using
End Function

<WpfTheory, CombinatorialData>
Public Async Function InvokeWithOpenAngleSeeCommitLangwordWithSpaceEqualsQuotes(showCompletionInArgumentLists As Boolean) As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document><![CDATA[
class c
{
/// <summary>
/// <see $$ =""
/// </summary>
void goo() { }
}
]]></Document>, showCompletionInArgumentLists:=showCompletionInArgumentLists)

state.SendTypeChars("l")
state.SendInvokeCompletionList()
Await state.AssertSelectedCompletionItem(displayText:="langword")
state.SendReturn()

' /// <see langword="$$" =""
Await state.AssertLineTextAroundCaret(" /// <see langword=""", """ =""""")
End Using
End Function

<WpfTheory, CombinatorialData>
Public Function InvokeWithNullKeywordCommitSeeLangword(showCompletionInArgumentLists As Boolean) As Task
Return InvokeWithKeywordCommitSeeLangword("null", showCompletionInArgumentLists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,29 @@ End Class
End Using
End Function

<WpfFact>
Public Async Function InvokeWithOpenAngleSeeCommitSeeWithEqualsQuotes() As Task
Using state = TestStateFactory.CreateVisualBasicTestState(
<Document><![CDATA[
Class C
''' <summary>
''' <see $$=""
''' </summary>
Sub Goo()
End Sub
End Class
]]></Document>)

state.SendTypeChars("l")
Await state.AssertCompletionSession()
Await state.AssertSelectedCompletionItem(displayText:="langword")
state.SendReturn()

' ''' <see langword="$$"
Await state.AssertLineTextAroundCaret(" ''' <see langword=""", """")
End Using
End Function

<WpfFact>
Public Async Function InvokeWithOpenAngleCommitSeeOnCloseAngle() As Task

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ public override bool IsInsertionTrigger(SourceText text, int characterPosition,

if (IsAttributeNameContext(token, position, out var elementName, out var existingAttributes))
{
return GetAttributeItems(elementName, existingAttributes);
var nextToken = token.GetNextToken();
return GetAttributeItems(elementName, existingAttributes,
addEqualsAndQuotes: !nextToken.IsKind(SyntaxKind.EqualsToken) || nextToken.HasLeadingTrivia);
}

var wasTriggeredAfterSpace = trigger.Kind == CompletionTriggerKind.Insertion && trigger.Character == ' ';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,14 @@ private CompletionItem GetItem(string name)
return CreateCompletionItem(name);
}

protected IEnumerable<CompletionItem> GetAttributeItems(string tagName, ISet<string> existingAttributes)
protected IEnumerable<CompletionItem> GetAttributeItems(string tagName, ISet<string> existingAttributes, bool addEqualsAndQuotes)
{
return s_attributeMap.Where(x => x.elementName == tagName && !existingAttributes.Contains(x.attributeName))
.Select(x => CreateCompletionItem(x.attributeName, beforeCaretText: x.text, afterCaretText: "\""));
return s_attributeMap
.Where(x => x.elementName == tagName && !existingAttributes.Contains(x.attributeName))
.Select(x => CreateCompletionItem(
x.attributeName,
beforeCaretText: addEqualsAndQuotes ? x.text : x.text[..^2],
afterCaretText: addEqualsAndQuotes ? "\"" : ""));
}

protected IEnumerable<CompletionItem> GetAlwaysVisibleItems()
Expand Down Expand Up @@ -279,6 +283,13 @@ public override async Task<CompletionChange> GetChangeAsync(Document document, C
var replacementText = beforeCaretText;
var newPosition = replacementSpan.Start + beforeCaretText.Length;

if (text.Length > replacementSpan.End + 1
&& text[replacementSpan.End] == '='
&& text[replacementSpan.End + 1] == '"')
{
newPosition += 2;
This conversation was marked as resolved.
Show resolved Hide resolved
}

if (commitChar.HasValue && !char.IsWhiteSpace(commitChar.Value) && commitChar.Value != replacementText[^1])
{
// include the commit character
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,20 +237,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers

If targetToken.IsChildToken(Function(n As XmlNameSyntax) n.LocalName) AndAlso targetToken.Parent Is tagNameSyntax Then
' <exception |
items.AddRange(GetAttributes(tagName, tagAttributes))
items.AddRange(GetAttributes(token, tagName, tagAttributes))
End If

'<exception a|
If targetToken.IsChildToken(Function(n As XmlNameSyntax) n.LocalName) AndAlso targetToken.Parent.IsParentKind(SyntaxKind.XmlAttribute) Then
' <exception |
items.AddRange(GetAttributes(tagName, tagAttributes))
items.AddRange(GetAttributes(token, tagName, tagAttributes))
End If

'<exception a=""|
If (targetToken.IsChildToken(Function(s As XmlStringSyntax) s.EndQuoteToken) AndAlso targetToken.Parent.IsParentKind(SyntaxKind.XmlAttribute)) OrElse
targetToken.IsChildToken(Function(a As XmlNameAttributeSyntax) a.EndQuoteToken) OrElse
targetToken.IsChildToken(Function(a As XmlCrefAttributeSyntax) a.EndQuoteToken) Then
items.AddRange(GetAttributes(tagName, tagAttributes))
items.AddRange(GetAttributes(token, tagName, tagAttributes))
End If

' <param name="|"
Expand Down Expand Up @@ -330,9 +330,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
Return TryCast(attribute, XmlNameAttributeSyntax)?.Reference?.Identifier.ValueText
End Function

Private Function GetAttributes(tagName As String, attributes As SyntaxList(Of XmlNodeSyntax)) As IEnumerable(Of CompletionItem)
Private Function GetAttributes(token As SyntaxToken, tagName As String, attributes As SyntaxList(Of XmlNodeSyntax)) As IEnumerable(Of CompletionItem)
Dim existingAttributeNames = attributes.Select(AddressOf GetAttributeName).WhereNotNull().ToSet()
Return GetAttributeItems(tagName, existingAttributeNames)
Dim nextToken = token.GetNextToken()
Return GetAttributeItems(tagName, existingAttributeNames,
addEqualsAndQuotes:=Not nextToken.IsKind(SyntaxKind.EqualsToken) Or nextToken.HasLeadingTrivia)
End Function

Private Shared Function GetAttributeName(node As XmlNodeSyntax) As String
Expand Down
Loading