提交 dfe76442 编写于 作者: C CyrusNajmabadi

Fix issue where we overly aggressively removed xml doc comment trivia.

上级 672f22f6
......@@ -153,7 +153,7 @@ public async Task RemovesDuplicateParamTag_BothParamTagsOnSameLine_WhitespaceBet
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
public async Task RemovesDuplicateParamTag_BothParamTagsOnSameLine_NothingBetweenThem()
public async Task RemovesDuplicateParamTag_BothParamTagsOnSameLine_NothingBetweenThem1()
{
var initial =
@"class Program
......@@ -179,6 +179,62 @@ public async Task RemovesDuplicateParamTag_BothParamTagsOnSameLine_NothingBetwee
await TestAsync(initial, expected);
}
[WorkItem(13436, "https://github.com/dotnet/roslyn/issues/13436")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
public async Task RemovesTag_BothParamTagsOnSameLine_NothingBetweenThem2()
{
var initial =
@"class Program
{
/// <summary>
///
/// </summary>
/// <param [|name=""a""|]></param><param name=""value""></param>
public void Fizz(int value) {}
}
";
var expected =
@"class Program
{
/// <summary>
///
/// </summary>
/// <param name=""value""></param>
public void Fizz(int value) {}
}
";
await TestAsync(initial, expected);
}
[WorkItem(13436, "https://github.com/dotnet/roslyn/issues/13436")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
public async Task RemovesTag_TrailingTextAfterTag()
{
var initial =
@"class Program
{
/// <summary>
///
/// </summary>
/// <param [|name=""a""|]></param> a
public void Fizz(int value) {}
}
";
var expected =
@"class Program
{
/// <summary>
///
/// </summary>
/// a
public void Fizz(int value) {}
}
";
await TestAsync(initial, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)]
public async Task RemovesDuplicateParamTag_RawTextBeforeAndAfterNode()
{
......
......@@ -135,7 +135,61 @@ End Class"
Sub Fizz(ByVal value As Integer)
End Sub
End Class"
Await TestAsync(initial, expected)
End Function
<WorkItem(13436, "https://github.com/dotnet/roslyn/issues/13436")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)>
Public Async Function RemovesParamTag_BothParamTagsOnSameLine() As Task
Dim initial =
"Class Program
''' <summary>
'''
''' </summary>
''' [|<param name=""a""></param>|]<param name=""value""></param>
Sub Fizz(ByVal value As Integer)
End Sub
End Class"
Dim expected =
"Class Program
''' <summary>
'''
''' </summary>
''' <param name=""value""></param>
Sub Fizz(ByVal value As Integer)
End Sub
End Class"
Await TestAsync(initial, expected)
End Function
<WorkItem(13436, "https://github.com/dotnet/roslyn/issues/13436")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveDocCommentNode)>
Public Async Function RemovesParamTag_TrailingText1() As Task
Dim initial =
"Class Program
''' <summary>
'''
''' </summary>
''' [|<param name=""a""></param>|] a
''' <param name=""value""></param>
Sub Fizz(ByVal value As Integer)
End Sub
End Class"
Dim expected =
"Class Program
''' <summary>
'''
''' </summary>
''' a
''' <param name=""value""></param>
Sub Fizz(ByVal value As Integer)
End Sub
End Class"
Await TestAsync(initial, expected)
End Function
......
// 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.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.CodeFixes;
......@@ -10,7 +11,8 @@ namespace Microsoft.CodeAnalysis.DiagnosticComments.CodeFixes
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.RemoveDocCommentNode), Shared]
[ExtensionOrder(After = PredefinedCodeFixProviderNames.ImplementInterface)]
internal class CSharpRemoveDocCommentNodeCodeFixProvider : AbstractRemoveDocCommentNodeCodeFixProvider<XmlElementSyntax>
internal class CSharpRemoveDocCommentNodeCodeFixProvider :
AbstractRemoveDocCommentNodeCodeFixProvider<XmlElementSyntax, XmlTextSyntax>
{
/// <summary>
/// Duplicate param tag
......@@ -33,5 +35,24 @@ internal class CSharpRemoveDocCommentNodeCodeFixProvider : AbstractRemoveDocComm
protected override SyntaxTriviaList GetRevisedDocCommentTrivia(string docCommentText)
=> SyntaxFactory.ParseLeadingTrivia(docCommentText);
protected override bool IsXmlWhitespaceToken(SyntaxToken token)
=> token.Kind() == SyntaxKind.XmlTextLiteralToken && IsWhitespace(token.Text);
protected override bool IsXmlNewLineToken(SyntaxToken token)
=> token.Kind() == SyntaxKind.XmlTextLiteralNewLineToken;
private bool IsWhitespace(string text)
{
foreach (var c in text)
{
if (!SyntaxFacts.IsWhitespace(c))
{
return false;
}
}
return true;
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
......@@ -12,8 +13,9 @@
namespace Microsoft.CodeAnalysis.DiagnosticComments.CodeFixes
{
internal abstract class AbstractRemoveDocCommentNodeCodeFixProvider<TXmlElementSyntax> : CodeFixProvider
internal abstract class AbstractRemoveDocCommentNodeCodeFixProvider<TXmlElementSyntax, TXmlTextSyntax> : CodeFixProvider
where TXmlElementSyntax : SyntaxNode
where TXmlTextSyntax : SyntaxNode
{
public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
......@@ -23,6 +25,9 @@ internal abstract class AbstractRemoveDocCommentNodeCodeFixProvider<TXmlElementS
protected abstract SyntaxTriviaList GetRevisedDocCommentTrivia(string docCommentText);
protected abstract bool IsXmlNewLineToken(SyntaxToken token);
protected abstract bool IsXmlWhitespaceToken(SyntaxToken token);
public async sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
......@@ -60,9 +65,8 @@ private TXmlElementSyntax GetParamNode(SyntaxNode root, TextSpan span, Cancellat
// If, perhaps, this specific node is not directly preceded by the comment marker node,
// it will be preceded by another XML node
var paramNodeIndex = paramNodeSiblings.IndexOf(paramNode);
var previousNodeTextTrimmed = paramNodeSiblings[paramNodeIndex - 1].ToFullString().Trim();
if (previousNodeTextTrimmed == string.Empty || previousNodeTextTrimmed == DocCommentSignifierToken)
if (ShouldRemovePreviousSibling(paramNodeSiblings, paramNodeIndex))
{
removedNodes.Add(paramNodeSiblings[paramNodeIndex - 1]);
}
......@@ -74,6 +78,49 @@ private TXmlElementSyntax GetParamNode(SyntaxNode root, TextSpan span, Cancellat
return document.WithSyntaxRoot(newRoot);
}
private bool ShouldRemovePreviousSibling(List<SyntaxNode> paramNodeSiblings, int paramNodeIndex)
{
if (paramNodeIndex > 0)
{
var previousNodeTextTrimmed = paramNodeSiblings[paramNodeIndex - 1].ToFullString().Trim();
if (previousNodeTextTrimmed == string.Empty ||
previousNodeTextTrimmed == DocCommentSignifierToken)
{
// Only remove the preceding /// if this param node is also the only thing on this line.
if (paramNodeIndex + 1 < paramNodeSiblings.Count)
{
var nextSibling = paramNodeSiblings[paramNodeIndex + 1];
var textSyntax = nextSibling as TXmlTextSyntax;
if (textSyntax != null)
{
// Walk the next text block forward, making sure we only see whitespace
// until we hit the next newline. If that's all we can remove the preceding
// '///'. Otherwise we'll want to keep it to keep whatever comes after
// this node valid.
foreach (var child in textSyntax.ChildNodesAndTokens())
{
Debug.Assert(child.IsToken, "All children of an XmlTextSyntax must be tokens");
if (IsXmlWhitespaceToken(child.AsToken()))
{
continue;
}
if (IsXmlNewLineToken(child.AsToken()))
{
return true;
}
return false;
}
}
}
}
}
return false;
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
......
......@@ -9,7 +9,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.DiagnosticComments.CodeFixes
<ExportCodeFixProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.RemoveDocCommentNode), [Shared]>
Friend Class VisualBasicRemoveDocCommentNodeCodeFixProvider
Inherits AbstractRemoveDocCommentNodeCodeFixProvider(Of XmlElementSyntax)
Inherits AbstractRemoveDocCommentNodeCodeFixProvider(Of XmlElementSyntax, XmlTextSyntax)
''' <summary>
''' XML comment tag with identical attributes
......@@ -58,5 +58,23 @@ Namespace Microsoft.CodeAnalysis.DiagnosticComments.CodeFixes
Protected Overrides Function GetRevisedDocCommentTrivia(docCommentText As String) As SyntaxTriviaList
Return SyntaxFactory.ParseLeadingTrivia(docCommentText)
End Function
Protected Overrides Function IsXmlWhitespaceToken(token As SyntaxToken) As Boolean
Return token.Kind() = SyntaxKind.XmlTextLiteralToken AndAlso IsWhitespace(token.Text)
End Function
Protected Overrides Function IsXmlNewLineToken(token As SyntaxToken) As Boolean
Return token.Kind() = SyntaxKind.DocumentationCommentLineBreakToken
End Function
Private Shared Function IsWhitespace(text As String) As Boolean
For Each c In text
If Not SyntaxFacts.IsWhitespace(c) Then
Return False
End If
Next
Return True
End Function
End Class
End Namespace
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册