Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trim unnessasary leading lines when removing usings #60672

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1984,5 +1984,144 @@ static void Main(string[] args)
LanguageVersion = LanguageVersion.CSharp10,
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)]
[WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")]
public async Task TestUsingGroups_DeleteLeadingBlankLinesIfFirstGroupWasDeleted_SingleUsing()
{
await new VerifyCS.Test
{
TestCode =
@"[|{|IDE0005:using System;|}

using System.Collections.Generic;|]

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
}
}
",
FixedCode =
@"using System.Collections.Generic;

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
}
}
"
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)]
[WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")]
public async Task TestUsingGroups_DeleteLeadingBlankLinesIfFirstGroupWasDeleted_MultipleUsings()
{
await new VerifyCS.Test
{
TestCode =
@"[|{|IDE0005:using System;
using System.Threading.Tasks;|}

using System.Collections.Generic;|]

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
}
}
",
FixedCode =
@"using System.Collections.Generic;

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
}
}
"
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)]
[WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")]
public async Task TestUsingGroups_NotAllFirstGroupIsDeleted()
{
await new VerifyCS.Test
{
TestCode =
@"[|{|IDE0005:using System;|}
using System.Threading.Tasks;

using System.Collections.Generic;|]

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
Task task = null;
}
}
",
FixedCode =
@"using System.Threading.Tasks;

using System.Collections.Generic;

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
Task task = null;
}
}
"
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)]
[WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")]
public async Task TestUsingGroups_AllLastGroupIsDeleted()
{
await new VerifyCS.Test
{
TestCode =
@"[|using System.Collections.Generic;

{|IDE0005:using System;
using System.Threading.Tasks;|}|]

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
}
}
",
FixedCode =
@"using System.Collections.Generic;

class Program
{
static void Main(string[] args)
{
var argList = new List<string>(args);
}
}
"
}.RunAsync();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1214,5 +1214,108 @@ Imports System
Event E()
End Class|]")
End Function

<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)>
<WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")>
Public Async Function TestImportGroup_DeleteLeadingBlankLinesIfFirstGroupWasDeleted_SingleImport() As Task
Await TestInRegularAndScript1Async(
"[|Imports System.Threading.Tasks

Imports System|]

Class C
Function Test()
Console.WriteLine()
End Function
End Class
",
"Imports System

Class C
Function Test()
Console.WriteLine()
End Function
End Class
")
End Function

<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)>
<WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")>
Public Async Function TestImportGroup_DeleteLeadingBlankLinesIfFirstGroupWasDeleted_MultipleImports() As Task
Await TestInRegularAndScript1Async(
"[|Imports System.Threading.Tasks
Imports System.Collections.Generic

Imports System|]

Class C
Function Test()
Console.WriteLine()
End Function
End Class
",
"Imports System

Class C
Function Test()
Console.WriteLine()
End Function
End Class
")
End Function

<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)>
<WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")>
Public Async Function TestImportGroup_NotAllFirstGroupIsDeleted() As Task
Await TestInRegularAndScript1Async(
"[|Imports System.Threading.Tasks
Imports System.Collections.Generic

Imports System|]

Class C
Function Test()
Console.WriteLine()
Dim list As List(Of Integer) = Nothing
End Function
End Class
",
"Imports System.Collections.Generic

Imports System

Class C
Function Test()
Console.WriteLine()
Dim list As List(Of Integer) = Nothing
End Function
End Class
")
End Function

<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryImports)>
<WorkItem(45866, "https://github.com/dotnet/roslyn/issues/45866")>
Public Async Function TestImportGroup_AllLastGroupIsDeleted() As Task
Await TestInRegularAndScript1Async(
"[|Imports System

Imports System.Threading.Tasks
Imports System.Collections.Generic|]

Class C
Function Test()
Console.WriteLine()
End Function
End Class
",
"Imports System

Class C
Function Test()
Console.WriteLine()
End Function
End Class
")
End Function
End Class
End Namespace
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
Expand Down Expand Up @@ -48,6 +47,8 @@ private static void ProcessUsings(
out SyntaxTriviaList finalTrivia)
{
var currentUsings = new List<UsingDirectiveSyntax>(usings);
var firstUsingNotBeingRemoved = true;
var passedLeadngTrivia = false;

finalTrivia = default;
for (var i = 0; i < usings.Count; i++)
Expand Down Expand Up @@ -83,13 +84,40 @@ private static void ProcessUsings(
// want to preserve.
currentUsings[nextIndex] = nextUsing.WithLeadingTrivia(leadingTrivia);
}

passedLeadngTrivia = true;
}
else
{
finalTrivia = leadingTrivia;
}
}
}
else if (firstUsingNotBeingRemoved)
{
// 1) We only apply this logic for not first using, that is saved:
// ===================
// namespace N;
//
// using System; <- if we save this using, we don't need to cut leading lines
// ===================
// 2) If leading trivia was saved from the previous using, that was removed,
// we don't bother cutting blank lines as well:
// ===================
// namespace N;
//
// using System; <- need to delete this using
// using System.Collections.Generic; <- this using is saved, no need to eat the line,
// otherwise https://github.com/dotnet/roslyn/issues/58972 will happen
if (i > 0 && !passedLeadngTrivia)
{
var currentUsing = currentUsings[i];
var currentUsingLeadingTrivia = currentUsing.GetLeadingTrivia();
currentUsings[i] = currentUsing.WithLeadingTrivia(currentUsingLeadingTrivia.WithoutLeadingBlankLines());
}

firstUsingNotBeingRemoved = false;
}
}

finalUsings = currentUsings.WhereNotNull().ToSyntaxList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports

Private Function ProcessImports(compilationUnit As CompilationUnitSyntax) As CompilationUnitSyntax
Dim oldImports = compilationUnit.Imports.ToList()
Dim firstImportNotBeingRemoved = True
Dim passedLeadingTrivia = False

Dim remainingTrivia As SyntaxTriviaList = Nothing
For i = 0 To oldImports.Count - 1
Expand All @@ -65,6 +67,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports
' want to preserve.
oldImports(nextIndex) = nextImport.WithLeadingTrivia(leadingTrivia)
End If

passedLeadingTrivia = True
Else
remainingTrivia = leadingTrivia
End If
Expand All @@ -85,6 +89,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports
oldImports(index) = previousImport.WithTrailingTrivia(trailingTrivia)
End If
End If
ElseIf firstImportNotBeingRemoved Then
' 1) We only apply this logic for Not first using, that is saved:
' ===================
' #Const A = 1
'
' Imports System <- if we save this import, we don't need to cut leading lines
' ===================
' 2) If leading trivia was saved from the previous import, that was removed,
' we don't bother cutting blank lines as well:
' ===================
' #Const A = 1
'
' Imports System <- need to delete this import
' Imports System.Collections.Generic <- this import is saved, no need to eat the line,
' otherwise https://github.com/dotnet/roslyn/issues/58972 will happen
If i > 0 AndAlso Not passedLeadingTrivia Then
Dim currentImport = oldImports(i)
Dim currentImportLeadingTrivia = currentImport.GetLeadingTrivia()
oldImports(i) = currentImport.WithLeadingTrivia(currentImportLeadingTrivia.WithoutLeadingWhitespaceOrEndOfLine())
End If

firstImportNotBeingRemoved = False
End If
Next

Expand Down