未验证 提交 be9d9fdb 编写于 作者: J Jinu 提交者: GitHub

Merge pull request #23576 from dabutvin/trim-newlines

trim extra lines between copyright and namespace (#23568)
......@@ -40,6 +40,32 @@ static void Main(string[] args)
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)]
public async Task TestNoReferencesWithCopyright()
{
await TestInRegularAndScriptAsync(
@"[|// Copyright (c) Somebody.
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
}
}|]",
@"// Copyright (c) Somebody.
class Program
{
static void Main(string[] args)
{
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)]
public async Task TestIdentifierReferenceInTypeContext()
{
......
......@@ -57,6 +57,27 @@ End Module|]",
End Module")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)>
Public Async Function TestNoImportsWithCopyright() As Task
Await TestInRegularAndScriptAsync(
"[|' Copyright (c) Somebody.
Imports System
Imports System.Collections.Generic
Imports System.Linq
Module Program
Sub Main(args As String())
End Sub
End Module|]",
"' Copyright (c) Somebody.
Module Program
Sub Main(args As String())
End Sub
End Module")
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)>
Public Async Function TestSimpleTypeName() As Task
Await TestInRegularAndScriptAsync(
......
......@@ -18,10 +18,18 @@ private class Rewriter : CSharpSyntaxRewriter
{
private readonly ISet<UsingDirectiveSyntax> _unnecessaryUsingsDoNotAccessDirectly;
private readonly CancellationToken _cancellationToken;
public Rewriter(ISet<UsingDirectiveSyntax> unnecessaryUsings, CancellationToken cancellationToken)
private readonly AbstractCSharpRemoveUnnecessaryImportsService _importsService;
private readonly Document _document;
public Rewriter(
AbstractCSharpRemoveUnnecessaryImportsService importsService,
Document document,
ISet<UsingDirectiveSyntax> unnecessaryUsings,
CancellationToken cancellationToken)
: base(visitIntoStructuredTrivia: true)
{
_importsService = importsService;
_document = document;
_unnecessaryUsingsDoNotAccessDirectly = unnecessaryUsings;
_cancellationToken = cancellationToken;
}
......@@ -116,7 +124,7 @@ public override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node)
// We've removed all the usings and now the first thing in the namespace is a
// type. In this case, remove any newlines preceding the type.
var firstToken = resultCompilationUnit.GetFirstToken();
var newFirstToken = StripNewLines(firstToken);
var newFirstToken = _importsService.StripNewLines(_document, firstToken);
resultCompilationUnit = resultCompilationUnit.ReplaceToken(firstToken, newFirstToken);
}
......@@ -150,17 +158,12 @@ public override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax
// We've removed all the usings and now the first thing in the namespace is a
// type. In this case, remove any newlines preceding the type.
var firstToken = resultNamespace.Members.First().GetFirstToken();
var newFirstToken = StripNewLines(firstToken);
var newFirstToken = _importsService.StripNewLines(_document, firstToken);
resultNamespace = resultNamespace.ReplaceToken(firstToken, newFirstToken);
}
return resultNamespace;
}
private static SyntaxToken StripNewLines(SyntaxToken firstToken)
{
return firstToken.WithLeadingTrivia(firstToken.LeadingTrivia.SkipWhile(t => t.Kind() == SyntaxKind.EndOfLineTrivia));
}
}
}
}
......@@ -37,7 +37,7 @@ internal partial class AbstractCSharpRemoveUnnecessaryImportsService :
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var oldRoot = (CompilationUnitSyntax)root;
var newRoot = (CompilationUnitSyntax)new Rewriter(unnecessaryImports, cancellationToken).Visit(oldRoot);
var newRoot = (CompilationUnitSyntax)new Rewriter(this, document, unnecessaryImports, cancellationToken).Visit(oldRoot);
cancellationToken.ThrowIfCancellationRequested();
return document.WithSyntaxRoot(await FormatResultAsync(document, newRoot, cancellationToken).ConfigureAwait(false));
......
......@@ -3,8 +3,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
......@@ -27,6 +29,24 @@ public Task<Document> RemoveUnnecessaryImportsAsync(Document document, Cancellat
return GetUnnecessaryImports(model, root, predicate: null, cancellationToken: cancellationToken).CastArray<SyntaxNode>();
}
protected SyntaxToken StripNewLines(Document document, SyntaxToken token)
{
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var trimmedLeadingTrivia = token.LeadingTrivia.SkipWhile(t => syntaxFacts.IsEndOfLineTrivia(t)).ToList();
// If the list ends with 3 newlines remove the last one until there's only 2 newlines to end the leading trivia.
while (trimmedLeadingTrivia.Count >= 3 &&
syntaxFacts.IsEndOfLineTrivia(trimmedLeadingTrivia[trimmedLeadingTrivia.Count - 3]) &&
syntaxFacts.IsEndOfLineTrivia(trimmedLeadingTrivia[trimmedLeadingTrivia.Count - 2]) &&
syntaxFacts.IsEndOfLineTrivia(trimmedLeadingTrivia[trimmedLeadingTrivia.Count - 1]))
{
trimmedLeadingTrivia.RemoveAt(trimmedLeadingTrivia.Count - 1);
}
return token.WithLeadingTrivia(trimmedLeadingTrivia);
}
protected abstract ImmutableArray<T> GetUnnecessaryImports(
SemanticModel model, SyntaxNode root,
Func<SyntaxNode, bool> predicate, CancellationToken cancellationToken);
......
......@@ -13,8 +13,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports
Private ReadOnly _unnecessaryImports As ISet(Of ImportsClauseSyntax)
Private ReadOnly _cancellationToken As CancellationToken
Private ReadOnly _annotation As New SyntaxAnnotation()
Public Sub New(unnecessaryImports As ISet(Of ImportsClauseSyntax), cancellationToken As CancellationToken)
Private ReadOnly _importsService As AbstractVisualBasicRemoveUnnecessaryImportsService
Private ReadOnly _document As Document
Public Sub New(importsService As AbstractVisualBasicRemoveUnnecessaryImportsService,
document As Document,
unnecessaryImports As ISet(Of ImportsClauseSyntax),
cancellationToken As CancellationToken)
_importsService = importsService
_document = document
_unnecessaryImports = unnecessaryImports
_cancellationToken = cancellationToken
End Sub
......@@ -105,18 +112,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports
If newCompilationUnit.Imports.Count = 0 AndAlso newCompilationUnit.Options.Count = 0 Then
If newCompilationUnit.Attributes.Count > 0 OrElse newCompilationUnit.Members.Count > 0 Then
Dim firstToken = newCompilationUnit.GetFirstToken()
Dim newFirstToken = StripNewLines(firstToken)
Dim newFirstToken = _importsService.StripNewLines(_document, firstToken)
newCompilationUnit = newCompilationUnit.ReplaceToken(firstToken, newFirstToken)
End If
End If
Return newCompilationUnit
End Function
Private Function StripNewLines(firstToken As SyntaxToken) As SyntaxToken
Return firstToken.WithLeadingTrivia(firstToken.LeadingTrivia.SkipWhile(
Function(t) t.Kind = SyntaxKind.EndOfLineTrivia))
End Function
End Class
End Class
End Namespace
......@@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports
Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False)
Dim oldRoot = DirectCast(root, CompilationUnitSyntax)
Dim newRoot = New Rewriter(unnecessaryImports, cancellationToken).Visit(oldRoot)
Dim newRoot = New Rewriter(Me, document, unnecessaryImports, cancellationToken).Visit(oldRoot)
newRoot = newRoot.WithAdditionalAnnotations(Formatter.Annotation)
cancellationToken.ThrowIfCancellationRequested()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册