提交 dcbaeae9 编写于 作者: C CyrusNajmabadi

Keep trivia declared on an individual declarator if we're removing it.

上级 4465cbb9
......@@ -627,6 +627,96 @@ void M()
}
}
}
}", compareTokens: false);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInlineDeclaration)]
public async Task TestComments4()
{
await TestAsync(
@"class C
{
void M()
{
int [|i|] /*suffix*/, j;
{
if (int.TryParse(v, out i))
{
}
}
}
}",
@"class C
{
void M()
{
int j;
{
if (int.TryParse(v, out int i /*suffix*/))
{
}
}
}
}", compareTokens: false);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInlineDeclaration)]
public async Task TestComments5()
{
await TestAsync(
@"class C
{
void M()
{
int /*prefix*/ [|i|], j;
{
if (int.TryParse(v, out i))
{
}
}
}
}",
@"class C
{
void M()
{
int j;
{
if (int.TryParse(v, out int /*prefix*/ i))
{
}
}
}
}", compareTokens: false);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInlineDeclaration)]
public async Task TestComments6()
{
await TestAsync(
@"class C
{
void M()
{
int /*prefix*/ [|i|] /*suffix*/, j;
{
if (int.TryParse(v, out i))
{
}
}
}
}",
@"class C
{
void M()
{
int j;
{
if (int.TryParse(v, out int /*prefix*/ i /*suffix*/))
{
}
}
}
}", compareTokens: false);
}
}
......
......@@ -17,6 +17,7 @@
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.InlineDeclaration
......@@ -67,6 +68,8 @@ private Task<Document> FixAsync(Document document, Diagnostic diagnostic, Cancel
Document document, SyntaxEditor editor, Diagnostic diagnostic,
bool useVarWhenDeclaringLocals, bool useImplicitTypeForIntrinsicTypes, CancellationToken cancellationToken)
{
var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var declaratorLocation = diagnostic.AdditionalLocations[0];
var identifierLocation = diagnostic.AdditionalLocations[1];
var invocationOrCreationLocation = diagnostic.AdditionalLocations[2];
......@@ -78,7 +81,8 @@ private Task<Document> FixAsync(Document document, Diagnostic diagnostic, Cancel
var outArgumentContainingStatement = (StatementSyntax)outArgumentContainingStatementLocation.FindNode(cancellationToken);
var declaration = (VariableDeclarationSyntax)declarator.Parent;
if (declaration.Variables.Count == 1)
var singleDeclarator = declaration.Variables.Count == 1;
if (singleDeclarator)
{
// Remove the entire declaration statement.
editor.RemoveNode(declaration.Parent);
......@@ -87,11 +91,24 @@ private Task<Document> FixAsync(Document document, Diagnostic diagnostic, Cancel
{
// Otherwise, just remove the single declarator.
editor.RemoveNode(declarator);
if (declarator == declaration.Variables[0])
{
// If we're removing the first declarator, and it's on the same line
// as the previous token, then we want to remove all the trivia belonging
// to the previous token. We're going to move it along with this declarator.
if (sourceText.AreOnSameLine(declarator.GetFirstToken(), declarator.GetFirstToken().GetPreviousToken(includeSkipped: true)))
{
editor.ReplaceNode(
declaration.Type,
(t, g) => t.WithTrailingTrivia(SyntaxFactory.ElasticSpace).WithoutAnnotations(Formatter.Annotation));
}
}
}
var newType = this.GetDeclarationType(declaration.Type, useVarWhenDeclaringLocals, useImplicitTypeForIntrinsicTypes);
var declarationExpression = GetDeclarationExpression(identifier, newType);
var declarationExpression = GetDeclarationExpression(
sourceText, identifier, newType, singleDeclarator ? null : declarator);
var semanticsChanged = await SemanticsChangedAsync(
document, declaration, invocationOrCreation, newType,
......@@ -105,7 +122,8 @@ private Task<Document> FixAsync(Document document, Diagnostic diagnostic, Cancel
// If the user originally wrote it something other than 'var', then use what they
// wrote. Otherwise, synthesize the actual type of the local.
var explicitType = declaration.Type.IsVar ? local.Type?.GenerateTypeSyntax() : declaration.Type;
declarationExpression = GetDeclarationExpression(identifier, explicitType);
declarationExpression = GetDeclarationExpression(
sourceText, identifier, explicitType, singleDeclarator ? null : declarator);
}
editor.ReplaceNode(identifier, declarationExpression);
......@@ -128,13 +146,31 @@ private Task<Document> FixAsync(Document document, Diagnostic diagnostic, Cancel
}
private static DeclarationExpressionSyntax GetDeclarationExpression(
IdentifierNameSyntax identifier, TypeSyntax newType)
SourceText sourceText, IdentifierNameSyntax identifier,
TypeSyntax newType, VariableDeclaratorSyntax declaratorOpt)
{
newType = newType.WithoutTrivia().WithAdditionalAnnotations(Formatter.Annotation);
var declarationExpression = SyntaxFactory.DeclarationExpression(
SyntaxFactory.TypedVariableComponent(
newType, SyntaxFactory.SingleVariableDesignation(identifier.Identifier)));
return declarationExpression;
var designation = SyntaxFactory.SingleVariableDesignation(identifier.Identifier);
if (declaratorOpt != null)
{
// We're removing a single declarator. Copy any comments it has to the out-var
// First, copy all the preceding trivia that's on the same line.
var precedingTrivia = declaratorOpt.GetAllPrecedingTriviaToPreviousToken(
sourceText, includePreviousTokenTrailingTriviaOnlyIfOnSameLine: true);
if (precedingTrivia.Any(t => t.IsSingleOrMultiLineComment()))
{
designation = designation.WithPrependedLeadingTrivia(precedingTrivia.Where(t => t.IsWhitespaceOrSingleOrMultiLineComment()));
}
if (declaratorOpt.GetTrailingTrivia().Any(t => t.IsSingleOrMultiLineComment()))
{
designation = designation.WithAppendedTrailingTrivia(declaratorOpt.GetTrailingTrivia().Where(t => t.IsWhitespaceOrSingleOrMultiLineComment()));
}
}
return SyntaxFactory.DeclarationExpression(
SyntaxFactory.TypedVariableComponent(newType, designation));
}
private async Task<bool> SemanticsChangedAsync(
......
......@@ -229,11 +229,19 @@ private static Matcher<SyntaxTrivia> Match(SyntaxKind kind, string description)
return Matcher.Single<SyntaxTrivia>(t => t.Kind() == kind, description);
}
public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(
this SyntaxNode node, SourceText sourceText = null,
bool includePreviousTokenTrailingTriviaOnlyIfOnSameLine = false)
=> node.GetFirstToken().GetAllPrecedingTriviaToPreviousToken(
sourceText, includePreviousTokenTrailingTriviaOnlyIfOnSameLine);
/// <summary>
/// Returns all of the trivia to the left of this token up to the previous token (concatenates
/// the previous token's trailing trivia and this token's leading trivia).
/// </summary>
public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(this SyntaxToken token)
public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(
this SyntaxToken token, SourceText sourceText = null,
bool includePreviousTokenTrailingTriviaOnlyIfOnSameLine = false)
{
var prevToken = token.GetPreviousToken(includeSkipped: true);
if (prevToken.Kind() == SyntaxKind.None)
......@@ -241,6 +249,12 @@ public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(thi
return token.LeadingTrivia;
}
if (includePreviousTokenTrailingTriviaOnlyIfOnSameLine &&
!sourceText.AreOnSameLine(prevToken, token))
{
return token.LeadingTrivia;
}
return prevToken.TrailingTrivia.Concat(token.LeadingTrivia);
}
......
......@@ -36,6 +36,9 @@ public static bool IsSingleOrMultiLineComment(this SyntaxTrivia trivia)
public static bool IsRegularComment(this SyntaxTrivia trivia)
=> trivia.IsSingleOrMultiLineComment() || trivia.IsShebangDirective();
public static bool IsWhitespaceOrSingleOrMultiLineComment(this SyntaxTrivia trivia)
=> trivia.IsWhitespace() || trivia.IsSingleOrMultiLineComment();
public static bool IsRegularOrDocComment(this SyntaxTrivia trivia)
{
return trivia.IsRegularComment() || trivia.IsDocComment();
......@@ -169,9 +172,12 @@ public static SyntaxTriviaList AsTrivia(this string s)
public static bool IsWhitespaceOrEndOfLine(this SyntaxTrivia trivia)
{
return trivia.Kind() == SyntaxKind.WhitespaceTrivia || trivia.Kind() == SyntaxKind.EndOfLineTrivia;
return IsWhitespace(trivia) || trivia.Kind() == SyntaxKind.EndOfLineTrivia;
}
public static bool IsWhitespace(this SyntaxTrivia trivia)
=> trivia.Kind() == SyntaxKind.WhitespaceTrivia;
public static SyntaxTrivia GetPreviousTrivia(
this SyntaxTrivia trivia, SyntaxTree syntaxTree, CancellationToken cancellationToken, bool findInsideTrivia = false)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册