提交 6c252e9c 编写于 作者: M Matt Warren

Add special handling for Implements and Inherts lists

上级 6eca7dcd
......@@ -362,50 +362,66 @@ public SeparatedSyntaxList<TNode> InsertRange(int index, IEnumerable<TNode> node
throw new ArgumentOutOfRangeException(nameof(index));
}
var nodesWithSeps = this.GetWithSeparators();
var nodesWithSeps = this.GetWithSeparators().ToList();
int insertionIndex = index < this.Count ? nodesWithSeps.IndexOf(this[index]) : nodesWithSeps.Count;
// determine how to deal with separators (commas)
if (insertionIndex > 0 && insertionIndex < nodesWithSeps.Count)
if (insertionIndex > 0 && insertionIndex - 1 < nodesWithSeps.Count)
{
// insert before nodes exsiting seperator if it doesn't have EOL trivia
// (if it does have EOL trivia, then assume it is sticky with the node)
var previous = nodesWithSeps[insertionIndex - 1];
if (previous.IsToken && !KeepSeparatorWithPreviousNode(previous.AsToken()))
if (previous.IsToken && !HasEndOfLine(previous.AsToken().TrailingTrivia))
{
// pull back so item in inserted before separator
insertionIndex--;
}
}
var nodesToInsertWithSeparators = new List<SyntaxNodeOrToken>();
foreach (var item in nodes)
{
if (item != null)
{
// if item before insertion point is a node, add a separator
if (nodesToInsertWithSeparators.Count > 0 || (insertionIndex > 0 && nodesWithSeps[insertionIndex - 1].IsNode))
if (insertionIndex > 0 && insertionIndex - 1 < nodesWithSeps.Count && nodesWithSeps[insertionIndex - 1].IsNode)
{
nodesToInsertWithSeparators.Add(item.Green.CreateSeparator<TNode>(item));
InsertSeparator(nodesWithSeps, insertionIndex);
insertionIndex++;
}
nodesToInsertWithSeparators.Add(item);
nodesWithSeps.Insert(insertionIndex, item);
insertionIndex++;
}
}
// if item after last inserted node is a node, add separator
if (insertionIndex < nodesWithSeps.Count && nodesWithSeps[insertionIndex].IsNode)
{
var node = nodesWithSeps[insertionIndex].AsNode();
nodesToInsertWithSeparators.Add(node.Green.CreateSeparator<TNode>(node)); // separator
InsertSeparator(nodesWithSeps, insertionIndex);
}
return new SeparatedSyntaxList<TNode>(nodesWithSeps.InsertRange(insertionIndex, nodesToInsertWithSeparators));
return new SeparatedSyntaxList<TNode>(default(SyntaxNodeOrTokenList).AddRange(nodesWithSeps));
}
private static void InsertSeparator(List<SyntaxNodeOrToken> list, int index)
{
Debug.Assert(index > 0);
var lastIndex = index - 1;
var sampleNode = list[lastIndex].AsNode();
// move trailing trivia of previous node to after separator
var movedTrivia = default(SyntaxTriviaList);
var separator = sampleNode.Green.CreateSeparator<TNode>(sampleNode);
var lastNode = list[lastIndex].AsNode();
movedTrivia = lastNode.GetTrailingTrivia();
list[lastIndex] = lastNode.WithTrailingTrivia();
separator = separator.WithTrailingTrivia(separator.TrailingTrivia.Concat(movedTrivia));
list.Insert(index, separator);
}
private static bool KeepSeparatorWithPreviousNode(SyntaxToken separator)
private static bool HasEndOfLine(SyntaxTriviaList list)
{
// if the trivia after the separator contains an explicit end of line or a single line comment
// then it should stay associated with previous node
foreach (var tr in separator.TrailingTrivia)
foreach (var tr in list)
{
if (tr.UnderlyingNode.IsTriviaWithEndOfLine())
{
......
......@@ -212,5 +212,34 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
Assert.Equal(-1, list.IndexOf(SyntaxKind.WhereClause))
Assert.False(list.Any(SyntaxKind.WhereClause))
End Sub
<Fact>
<WorkItem(5097, "https://github.com/dotnet/roslyn/issues/5097")>
Public Sub InsertInterfaceAtEndOfImplementsClause()
' prove that comma is inserted before EOL
Dim cu = SyntaxFactory.ParseCompilationUnit("
Class C
Implements I
End Class")
Dim iface = cu.DescendantNodes().OfType(Of IdentifierNameSyntax).First(Function(id) id.Identifier.Text = "I")
Dim xface = SyntaxFactory.ParseExpression("X")
Dim newcu = cu.InsertNodesAfter(iface, {xface})
Assert.Equal("
Class C
Implements I,
XEnd Class", newcu.ToFullString())
Dim normal = newcu.NormalizeWhitespace()
Dim expected = "Class C
Implements I, X
End Class
"
Assert.Equal(expected, normal.ToFullString())
End Sub
End Class
End Namespace
......@@ -3332,21 +3332,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
If declaration.IsKind(SyntaxKind.InterfaceBlock) Then
Dim inh = Me.GetInherits(declaration)
Dim last = inh.SelectMany(Function(s) s.Types).LastOrDefault()
If last IsNot Nothing Then
Return InsertNodesAfter(declaration, last, {interfaceType})
If inh.Count = 1 AndAlso last IsNot Nothing Then
Dim inh0 = inh(0)
Dim newInh0 = PreserveTrivia(inh0.TrackNodes(last), Function(_inh0) InsertNodesAfter(_inh0, _inh0.GetCurrentNode(last), {interfaceType}))
Return ReplaceNode(declaration, inh0, newInh0)
Else
Return Me.WithInherits(declaration, inh.Add(SyntaxFactory.InheritsStatement(DirectCast(interfaceType, TypeSyntax))))
End If
Else
Dim imp = Me.GetImplements(declaration)
Dim last = imp.SelectMany(Function(s) s.Types).LastOrDefault()
If last IsNot Nothing Then
Return InsertNodesAfter(declaration, last, {interfaceType})
If imp.Count = 1 AndAlso last IsNot Nothing Then
Dim imp0 = imp(0)
Dim newImp0 = PreserveTrivia(imp0.TrackNodes(last), Function(_imp0) InsertNodesAfter(_imp0, _imp0.GetCurrentNode(last), {interfaceType}))
Return ReplaceNode(declaration, imp0, newImp0)
Else
Return Me.WithImplements(declaration, imp.Add(SyntaxFactory.ImplementsStatement(DirectCast(interfaceType, TypeSyntax))))
End If
End If
Throw New NotImplementedException()
End Function
Private Function GetInherits(declaration As SyntaxNode) As SyntaxList(Of InheritsStatementSyntax)
......
......@@ -39,8 +39,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Editting
Private Sub VerifySyntaxRaw(Of TSyntax As SyntaxNode)(type As SyntaxNode, expectedText As String)
Assert.IsAssignableFrom(GetType(TSyntax), type)
Dim normalized = type.ToFullString()
Assert.Equal(expectedText, normalized)
Dim text = type.ToFullString()
Assert.Equal(expectedText, text)
End Sub
Private Function ParseCompilationUnit(text As String) As CompilationUnitSyntax
......@@ -2785,6 +2785,77 @@ End Interface</x>.Value)
End Sub
<Fact>
<WorkItem(5097, "https://github.com/dotnet/roslyn/issues/5097")>
Public Sub TestAddInterfaceWithEOLs()
Dim classC = SyntaxFactory.ParseCompilationUnit("
Public Class C
End Class").Members(0)
VerifySyntaxRaw(Of ClassBlockSyntax)(
_g.AddInterfaceType(classC, _g.IdentifierName("X")), "
Public Class C
ImplementsXEnd Class")
Dim interfaceI = SyntaxFactory.ParseCompilationUnit("
Public Interface I
End Interface").Members(0)
VerifySyntaxRaw(Of InterfaceBlockSyntax)(
_g.AddInterfaceType(interfaceI, _g.IdentifierName("X")), "
Public Interface I
InheritsXEnd Interface")
Dim classCX = SyntaxFactory.ParseCompilationUnit("
Public Class C
Implements X
End Class").Members(0)
VerifySyntaxRaw(Of ClassBlockSyntax)(
_g.AddInterfaceType(classCX, _g.IdentifierName("Y")), "
Public Class C
Implements X,Y
End Class")
Dim interfaceIX = SyntaxFactory.ParseCompilationUnit("
Public Interface I
Inherits X
End Interface").Members(0)
VerifySyntaxRaw(Of InterfaceBlockSyntax)(
_g.AddInterfaceType(interfaceIX, _g.IdentifierName("Y")), "
Public Interface I
Inherits X,Y
End Interface")
Dim classCXY = SyntaxFactory.ParseCompilationUnit("
Public Class C
Implements X
Implements Y
End Class").Members(0)
VerifySyntaxRaw(Of ClassBlockSyntax)(
_g.AddInterfaceType(classCXY, _g.IdentifierName("Z")), "
Public Class C
Implements X
Implements Y
ImplementsZEnd Class")
Dim interfaceIXY = SyntaxFactory.ParseCompilationUnit("
Public Interface I
Inherits X
Inherits Y
End Interface").Members(0)
VerifySyntaxRaw(Of InterfaceBlockSyntax)(
_g.AddInterfaceType(interfaceIXY, _g.IdentifierName("Z")), "
Public Interface I
Inherits X
Inherits Y
InheritsZEnd Interface")
End Sub
<Fact>
Public Sub TestMultiFieldMembers()
Dim comp = Compile(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册