提交 7d984c02 编写于 作者: C CyrusNajmabadi

Get comments working well when moving declaration.

上级 f9029c7c
......@@ -25,6 +25,7 @@ private class State
public ILocalSymbol LocalSymbol { get; private set; }
public SyntaxNode OutermostBlock { get; private set; }
public SyntaxNode InnermostBlock { get; private set; }
public SyntaxList<TStatementSyntax> OutermostBlockStatements { get; private set; }
public SyntaxList<TStatementSyntax> InnermostBlockStatements { get; private set; }
public TStatementSyntax FirstStatementAffectedInInnermostBlock { get; private set; }
......@@ -113,6 +114,7 @@ private class State
}
this.InnermostBlockStatements = syntaxFacts.GetExecutableBlockStatements(this.InnermostBlock);
this.OutermostBlockStatements = syntaxFacts.GetExecutableBlockStatements(this.OutermostBlock);
var allAffectedStatements = new HashSet<TStatementSyntax>(referencingStatements.SelectMany(
expr => expr.GetAncestorsOrThis<TStatementSyntax>()));
......
// 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;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
......@@ -80,37 +83,71 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
var canMergeDeclarationAndAssignment = await CanMergeDeclarationAndAssignmentAsync(document, state, cancellationToken).ConfigureAwait(false);
if (canMergeDeclarationAndAssignment)
{
// Replace the first reference with a new declaration.
var declarationStatement = CreateMergedDeclarationStatement(state.DeclarationStatement, state.FirstStatementAffectedInInnermostBlock);
declarationStatement = warningAnnotation == null
? declarationStatement
: declarationStatement.WithAdditionalAnnotations(warningAnnotation);
editor.ReplaceNode(
state.FirstStatementAffectedInInnermostBlock,
declarationStatement.WithAdditionalAnnotations(Formatter.Annotation));
MergeDeclarationAndAssignment(state, editor, warningAnnotation);
}
else
{
// If we're not merging with an existing declaration, make the declaration semantically
// explicit to improve the chances that it won't break code.
var explicitDeclarationStatement = await Simplifier.ExpandAsync(
state.DeclarationStatement, document, cancellationToken: cancellationToken).ConfigureAwait(false);
// place the declaration above the first statement that references it.
var declarationStatement = warningAnnotation == null
? explicitDeclarationStatement
: explicitDeclarationStatement.WithAdditionalAnnotations(warningAnnotation);
editor.InsertBefore(
state.FirstStatementAffectedInInnermostBlock,
declarationStatement.WithAdditionalAnnotations(Formatter.Annotation));
await MoveDeclarationToFirstReferenceAsync(
document, state, editor, warningAnnotation, cancellationToken).ConfigureAwait(false);
}
var newRoot = editor.GetChangedRoot();
return document.WithSyntaxRoot(newRoot);
}
private static async Task MoveDeclarationToFirstReferenceAsync(Document document, State state, SyntaxEditor editor, SyntaxAnnotation warningAnnotation, CancellationToken cancellationToken)
{
// If we're not merging with an existing declaration, make the declaration semantically
// explicit to improve the chances that it won't break code.
var explicitDeclarationStatement = await Simplifier.ExpandAsync(
state.DeclarationStatement, document, cancellationToken: cancellationToken).ConfigureAwait(false);
// place the declaration above the first statement that references it.
var declarationStatement = warningAnnotation == null
? explicitDeclarationStatement
: explicitDeclarationStatement.WithAdditionalAnnotations(warningAnnotation);
declarationStatement = declarationStatement.WithAdditionalAnnotations(Formatter.Annotation);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var newNextStatement = state.FirstStatementAffectedInInnermostBlock;
declarationStatement = declarationStatement.WithPrependedLeadingTrivia(
syntaxFacts.GetLeadingBlankLines(newNextStatement));
editor.InsertBefore(
state.FirstStatementAffectedInInnermostBlock,
declarationStatement);
editor.ReplaceNode(
newNextStatement,
newNextStatement.WithAdditionalAnnotations(Formatter.Annotation).WithLeadingTrivia(
newNextStatement.GetLeadingTrivia().Skip(syntaxFacts.GetLeadingBlankLines(newNextStatement).Length)));
// Move leading whitespace from the declaration statement to the next statement.
var statementIndex = state.OutermostBlockStatements.IndexOf(state.DeclarationStatement);
if (statementIndex + 1 < state.OutermostBlockStatements.Count)
{
var originalNextStatement = state.OutermostBlockStatements[statementIndex + 1];
editor.ReplaceNode(
originalNextStatement,
(current, generator) => current.WithAdditionalAnnotations(Formatter.Annotation).WithPrependedLeadingTrivia(
syntaxFacts.GetLeadingBlankLines(state.DeclarationStatement)));
}
}
private void MergeDeclarationAndAssignment(State state, SyntaxEditor editor, SyntaxAnnotation warningAnnotation)
{
// Replace the first reference with a new declaration.
var declarationStatement = CreateMergedDeclarationStatement(state.DeclarationStatement, state.FirstStatementAffectedInInnermostBlock);
declarationStatement = warningAnnotation == null
? declarationStatement
: declarationStatement.WithAdditionalAnnotations(warningAnnotation);
editor.ReplaceNode(
state.FirstStatementAffectedInInnermostBlock,
declarationStatement.WithAdditionalAnnotations(Formatter.Annotation));
}
private bool CrossesMeaningfulBlock(State state)
{
var blocks = state.InnermostBlock.GetAncestorsOrThis<SyntaxNode>();
......
......@@ -270,6 +270,9 @@ private bool IsOnSingleLine(string value)
public abstract bool IsStringLiteral(SyntaxToken token);
public abstract bool IsInterpolatedStringTextToken(SyntaxToken token);
public ImmutableArray<SyntaxTrivia> GetLeadingBlankLines(SyntaxNode node)
=> GetLeadingBlankLines<SyntaxNode>(node);
public ImmutableArray<SyntaxTrivia> GetLeadingBlankLines<TSyntaxNode>(TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
......
......@@ -298,6 +298,9 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode GetNextExecutableStatement(SyntaxNode statement);
ImmutableArray<SyntaxTrivia> GetLeadingBlankLines(SyntaxNode node);
TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(TSyntaxNode node) where TSyntaxNode : SyntaxNode;
ImmutableArray<SyntaxTrivia> GetFileBanner(SyntaxNode root);
bool ContainsInterleavedDirective(SyntaxNode node, CancellationToken cancellationToken);
......
......@@ -1631,5 +1631,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Public Function FindInnermostCommonExecutableBlock(nodes As IEnumerable(Of SyntaxNode)) As SyntaxNode Implements ISyntaxFactsService.FindInnermostCommonExecutableBlock
Return nodes.FindInnermostCommonExecutableBlock()
End Function
Private Function ISyntaxFactsService_GetLeadingBlankLines(node As SyntaxNode) As ImmutableArray(Of SyntaxTrivia) Implements ISyntaxFactsService.GetLeadingBlankLines
Return MyBase.GetLeadingBlankLines(node)
End Function
Private Function ISyntaxFactsService_GetNodeWithoutLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As TSyntaxNode Implements ISyntaxFactsService.GetNodeWithoutLeadingBlankLines
Return MyBase.GetNodeWithoutLeadingBlankLines(node)
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册