提交 2f433228 编写于 作者: C CyrusNajmabadi

Don't cause braces to become imbalanced when populating a switch statement.

上级 02fe2da8
......@@ -1015,6 +1015,11 @@ public bool IsObjectInitializerNamedAssignmentIdentifier(SyntaxNode node, out Sy
{
throw new NotImplementedException();
}
public void AddFirstMissingCloseBrace(SyntaxNode root, SyntaxNode contextNode, out SyntaxNode newRoot, out SyntaxNode newContextNode)
{
throw new NotImplementedException();
}
}
}
}
......
using System;
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
......@@ -895,6 +897,7 @@ void Method()
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsPopulateSwitch)]
[WorkItem(13455, "https://github.com/dotnet/roslyn/issues/13455")]
public async Task AllMissingTokens()
{
await TestAsync(
......@@ -928,7 +931,7 @@ void Method()
break;
}
}
");
}", compareTokens: false);
}
}
}
\ No newline at end of file
using Roslyn.Test.Utilities;
// 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 Roslyn.Test.Utilities;
using System.Threading.Tasks;
using Xunit;
......
......@@ -891,6 +891,10 @@ End Class]]></a>.Value.NormalizeLineEndings()
Public Function ConvertToSingleLine(node As SyntaxNode, Optional useElasticTrivia As Boolean = False) As SyntaxNode Implements ISyntaxFactsService.ConvertToSingleLine
Throw New NotImplementedException()
End Function
Public Sub AddFirstMissingCloseBrace(root As SyntaxNode, contextNode As SyntaxNode, ByRef newRoot As SyntaxNode, ByRef newContextNode As SyntaxNode) Implements ISyntaxFactsService.AddFirstMissingCloseBrace
Throw New NotImplementedException()
End Sub
End Class
End Class
End Namespace
......@@ -14,7 +14,9 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Semantics;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;
......@@ -111,10 +113,34 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
var newSwitchNode = generator.InsertSwitchSections(switchNode, insertLocation, newSections)
.WithAdditionalAnnotations(Formatter.Annotation);
// Make sure we didn't cause any braces to be imbalanced when we added members
// to the switch.
AddMissingBraces(document, ref root, ref switchNode);
var newRoot = root.ReplaceNode(switchNode, newSwitchNode);
return document.WithSyntaxRoot(newRoot);
}
private void AddMissingBraces(
Document document,
ref SyntaxNode root,
ref SyntaxNode switchNode)
{
// Parsing of the switch may have caused imbalanced braces. i.e. the switch
// may have consumed a brace that was intended for a higher level construct.
// So balance the tree first, then do the switch replacement.
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
SyntaxNode newRoot;
SyntaxNode newSwitchNode;
syntaxFacts.AddFirstMissingCloseBrace(
root, switchNode, out newRoot, out newSwitchNode);
root = newRoot;
switchNode = newSwitchNode;
}
private int InsertPosition(ISwitchStatement switchStatement)
{
// If the last section has a default label, then we want to be above that.
......
......@@ -11,6 +11,7 @@
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
......@@ -1760,5 +1761,88 @@ public bool IsDeclaration(SyntaxNode node)
{
return SyntaxFacts.IsNamespaceMemberDeclaration(node.Kind()) || IsMemberDeclaration(node);
}
private static readonly SyntaxAnnotation s_annotation = new SyntaxAnnotation();
public void AddFirstMissingCloseBrace(
SyntaxNode root, SyntaxNode contextNode,
out SyntaxNode newRoot, out SyntaxNode newContextNode)
{
// First, annotate the context node in the tree so that we can find it again
// after we've done all the rewriting.
// var currentRoot = root.ReplaceNode(contextNode, contextNode.WithAdditionalAnnotations(s_annotation));
newRoot = new AddFirstMissingCloseBaceRewriter(contextNode).Visit(root);
newContextNode = newRoot.GetAnnotatedNodes(s_annotation).Single();
}
private class AddFirstMissingCloseBaceRewriter: CSharpSyntaxRewriter
{
private readonly SyntaxNode _contextNode;
private bool _seenContextNode = false;
private bool _addedFirstCloseCurly = false;
public AddFirstMissingCloseBaceRewriter(SyntaxNode contextNode)
{
_contextNode = contextNode;
}
public override SyntaxNode Visit(SyntaxNode node)
{
if (node == _contextNode)
{
_seenContextNode = true;
// Annotate the context node so we can find it again in the new tree
// after we've added the close curly.
return node.WithAdditionalAnnotations(s_annotation);
}
// rewrite this node normally.
var rewritten = base.Visit(node);
if (rewritten == node)
{
return rewritten;
}
// This node changed. That means that something underneath us got
// rewritten. (i.e. we added the annotation to the context node).
Debug.Assert(_seenContextNode);
// Ok, we're past the context node now. See if this is a node with
// curlies. If so, if it has a missing close curly then add in the
// missing curly. Also, even if it doesn't have missing curlies,
// then still ask to format its close curly to make sure all the
// curlies up the stack are properly formatted.
var braces = rewritten.GetBraces();
if (braces.Item1.Kind() == SyntaxKind.None &&
braces.Item2.Kind() == SyntaxKind.None)
{
// Not an item with braces. Just pass it up.
return rewritten;
}
// See if the close brace is missing. If it's the first missing one
// we're seeing then definitely add it.
if (braces.Item2.IsMissing)
{
if (!_addedFirstCloseCurly)
{
var closeBrace = SyntaxFactory.Token(SyntaxKind.CloseBraceToken)
.WithAdditionalAnnotations(Formatter.Annotation);
rewritten = rewritten.ReplaceToken(braces.Item2, closeBrace);
_addedFirstCloseCurly = true;
}
}
else
{
// Ask for the close brace to be formatted so that all the braces
// up the spine are in the right location.
rewritten = rewritten.ReplaceToken(braces.Item2,
braces.Item2.WithAdditionalAnnotations(Formatter.Annotation));
}
return rewritten;
}
}
}
}
}
\ No newline at end of file
......@@ -185,6 +185,14 @@ internal interface ISyntaxFactsService : ILanguageService
/// that arguments name.
/// </summary>
string GetNameForArgument(SyntaxNode argument);
// Walks the tree, starting from contextNode, looking for the first construct
// with a missing close brace. If found, the close brace will be added and the
// updates root will be returned. The context node in that new tree will also
// be returned.
void AddFirstMissingCloseBrace(
SyntaxNode root, SyntaxNode contextNode,
out SyntaxNode newRoot, out SyntaxNode newContextNode);
}
[Flags]
......
......@@ -1456,5 +1456,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return False
End Function
Public Sub AddFirstMissingCloseBrace(root As SyntaxNode, contextNode As SyntaxNode, ByRef newRoot As SyntaxNode, ByRef newContextNode As SyntaxNode) Implements ISyntaxFactsService.AddFirstMissingCloseBrace
' Nothing to be done. VB doesn't have close braces
newRoot = root
newContextNode = contextNode
End Sub
End Class
End Namespace
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.
先完成此消息的编辑!
想要评论请 注册