提交 c5cbb3a8 编写于 作者: C Cyrus Najmabadi

Address bugs in impl

上级 c081ce75
......@@ -17,7 +17,7 @@
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.UseSimpleUsingDeclaration
namespace Microsoft.CodeAnalysis.CSharp.UseSimpleUsingStatement
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseSimpleUsingStatementCodeFixProvider)), Shared]
internal class UseSimpleUsingStatementCodeFixProvider : SyntaxEditorBasedCodeFixProvider
......@@ -38,9 +38,23 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
Document document, ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor, CancellationToken cancellationToken)
{
var usingStatements = diagnostics.Select(d => (UsingStatementSyntax)d.AdditionalLocations[0].FindNode(cancellationToken)).ToSet();
var rewriter = new Rewriter(usingStatements);
var directUsingStatements = diagnostics.SelectAsArray(d => (UsingStatementSyntax)d.AdditionalLocations[0].FindNode(cancellationToken));
// Grab all the convertible usings in a block of nested usings. i.e.
//
// using (...)
// using (...)
// using (...)
// {
// }
//
// If invoked on any of these , we'll convert in all in teh group that we can.
// Importantly, this is a set, so if we're doing a fix-all, we may add the items
// multiple times, but that's ok as it will still only be in the set once.
var allUsingStatements = GetUsingStatementsToUpdate(directUsingStatements);
var rewriter = new Rewriter(allUsingStatements);
var root = editor.OriginalRoot;
var updatedRoot = rewriter.Visit(root);
......@@ -49,6 +63,29 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
return Task.CompletedTask;
}
private static HashSet<UsingStatementSyntax> GetUsingStatementsToUpdate(ImmutableArray<UsingStatementSyntax> directUsingStatements)
{
var allUsingStatements = new HashSet<UsingStatementSyntax>();
foreach (var usingStatement in directUsingStatements)
{
// First, walk up to the topmost using statement in this chain that is convertible
var topmostUsingStatement = (UsingStatementSyntax)usingStatement.AncestorsAndSelf().TakeWhile(
n => n is UsingStatementSyntax ancestor &&
UseSimpleUsingStatementDiagnosticAnalyzer.CanConvertUsingStatement(ancestor)).Last();
// Then walk inwards adding all using statements that are convertible.
for (var current = topmostUsingStatement;
current != null && UseSimpleUsingStatementDiagnosticAnalyzer.CanConvertUsingStatement(current);
current = current.Statement as UsingStatementSyntax)
{
allUsingStatements.Add(current);
}
}
return allUsingStatements;
}
private class Rewriter : CSharpSyntaxRewriter
{
private readonly ISet<UsingStatementSyntax> _usingStatements;
......@@ -91,29 +128,6 @@ private static LocalDeclarationStatementSyntax Convert(UsingStatementSyntax usin
SyntaxFactory.Token(SyntaxKind.SemicolonToken));
}
public override SyntaxNode VisitElseClause(ElseClauseSyntax node)
{
// First, descend into the else-clause so we fixup any using statements contained
// inside of it.
var rewrittenElse = (ElseClauseSyntax)base.VisitElseClause(node);
// Now, if the else-clause previous pointed at a using statement we wanted to
// rewrite, and it still points at a using statement, then expand that using
// statemnet into the else-clause.
var rewrittenStatement = rewrittenElse.Statement;
if (ShouldExpand(node.Statement, rewrittenStatement))
{
// Can't expand a using-statement directly inside an else-clause.
// have to add a block around it to make sure scoping is preserved
// properly.
var expanded = Expand((UsingStatementSyntax)rewrittenStatement);
return rewrittenElse.WithStatement(SyntaxFactory.Block(expanded))
.WithAdditionalAnnotations(Formatter.Annotation);
}
return rewrittenElse;
}
private bool ExpandAppropriateStatements(
SyntaxList<StatementSyntax> originalStatements,
SyntaxList<StatementSyntax> rewrittenStatements,
......@@ -166,29 +180,27 @@ private SyntaxNode VisitBlockWorker(BlockSyntax node, ArrayBuilder<StatementSynt
.WithAdditionalAnnotations(Formatter.Annotation);
}
public override SyntaxNode VisitSwitchSection(SwitchSectionSyntax node)
public override SyntaxNode VisitUsingStatement(UsingStatementSyntax node)
{
var finalStatements = ArrayBuilder<StatementSyntax>.GetInstance();
var result = VisitSwitchSectionWorker(node, finalStatements);
finalStatements.Free();
return result;
}
private SyntaxNode VisitSwitchSectionWorker(SwitchSectionSyntax node, ArrayBuilder<StatementSyntax> finalStatements)
{
var rewrittenSwitchSection = (SwitchSectionSyntax)base.VisitSwitchSection(node);
var changed = ExpandAppropriateStatements(node.Statements, rewrittenSwitchSection.Statements, finalStatements);
// First, descend into the using-statement so we fixup any using statements contained
// inside of it.
var rewrittenUsingStatement = (UsingStatementSyntax)base.VisitUsingStatement(node);
if (!changed)
// Now, if the else-clause previous pointed at a using statement we wanted to
// rewrite, and it still points at a using statement, then expand that using
// statemnet into the else-clause.
var rewrittenStatement = rewrittenUsingStatement.Statement;
if (ShouldExpand(node.Statement, rewrittenStatement))
{
// Didn't update any children. Just return as is.
return rewrittenSwitchSection;
// Can't expand a using-statement directly inside an else-clause.
// have to add a block around it to make sure scoping is preserved
// properly.
var expanded = Expand((UsingStatementSyntax)rewrittenStatement);
return rewrittenUsingStatement.WithStatement(SyntaxFactory.Block(expanded))
.WithAdditionalAnnotations(Formatter.Annotation);
}
return rewrittenSwitchSection.WithStatements(new SyntaxList<StatementSyntax>(finalStatements))
.WithAdditionalAnnotations(Formatter.Annotation);
return rewrittenUsingStatement;
}
}
......
......@@ -30,10 +30,6 @@ protected override void InitializeWorker(AnalysisContext context)
private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
{
var usingStatement = (UsingStatementSyntax)context.Node;
if (usingStatement.Declaration == null)
{
return;
}
var syntaxTree = context.Node.SyntaxTree;
//var options = (CSharpParseOptions)syntaxTree.Options;
......@@ -55,12 +51,28 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
return;
}
if (CanConvertUsingStatement(usingStatement))
{
context.ReportDiagnostic(DiagnosticHelper.Create(
Descriptor,
usingStatement.UsingKeyword.GetLocation(),
option.Notification.Severity,
additionalLocations: ImmutableArray.Create(usingStatement.GetLocation()),
properties: null));
}
}
public static bool CanConvertUsingStatement(UsingStatementSyntax usingStatement)
{
if (usingStatement.Declaration == null)
{
return false;
}
var parent = usingStatement.Parent;
var okParent = parent is BlockSyntax ||
parent is SwitchSectionSyntax;
if (!okParent)
if (!(parent is BlockSyntax || parent is UsingStatementSyntax))
{
return;
return false;
}
// Has to be one of the following forms:
......@@ -72,22 +84,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
// the resource, instead of afterwards. Effectly, the statement following
// cannot actually execute any code that might depend on the .Dispose method
// being called or not.
var statements = GetStatements(parent, usingStatement);
if (CanConvertUsingStatement(statements, usingStatement))
{
context.ReportDiagnostic(DiagnosticHelper.Create(
Descriptor,
usingStatement.UsingKeyword.GetLocation(),
option.Notification.Severity,
additionalLocations: ImmutableArray.Create(usingStatement.GetLocation()),
properties: null));
}
}
var statements = GetStatements(parent);
private bool CanConvertUsingStatement(
SyntaxList<StatementSyntax> statements,
UsingStatementSyntax usingStatement)
{
var index = statements.IndexOf(usingStatement);
if (index == statements.Count - 1)
{
......@@ -123,12 +121,12 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
return false;
}
private SyntaxList<StatementSyntax> GetStatements(SyntaxNode parent, UsingStatementSyntax usingStatement)
private static SyntaxList<StatementSyntax> GetStatements(SyntaxNode parent)
{
switch (parent)
{
case BlockSyntax block: return block.Statements;
case SwitchSectionSyntax switchSection: return switchSection.Statements;
case UsingStatementSyntax usingStatement: return new SyntaxList<StatementSyntax>(usingStatement.Statement);
default: throw ExceptionUtilities.UnexpectedValue(parent);
}
}
......
......@@ -2475,7 +2475,7 @@ Tato verze se používá zde: {2}.</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ Diese Version wird verwendet in: {2}</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ Esta versión se utiliza en: {2}</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ Version utilisée dans : {2}</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ Questa versione è usata {2}</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ This version used in: {2}</source>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ This version used in: {2}</source>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ Ta wersja jest używana wersja: {2}</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ Essa versão é usada no: {2}</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ This version used in: {2}</source>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ Bu sürüm şurada kullanılır: {2}</target>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ This version used in: {2}</source>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
......@@ -2475,7 +2475,7 @@ This version used in: {2}</source>
<target state="new">updating usages in dependent projects</target>
<note />
</trans-unit>
<trans-unit id="using_statment_can_be_simplified">
<trans-unit id="using_statement_can_be_simplified">
<source>'using' statement can be simplified</source>
<target state="new">'using' statement can be simplified</target>
<note />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册