Skip to content

Commit

Permalink
Merge pull request dotnet#14674 from CyrusNajmabadi/addUsingTrivia
Browse files Browse the repository at this point in the history
Keep doc comments at top of file when adding usings.
  • Loading branch information
CyrusNajmabadi authored Oct 21, 2016
2 parents 0a6a4c0 + 2033111 commit e5ebda7
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2356,6 +2356,91 @@ public class N { }
}");
}

[WorkItem(226826, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=226826")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddUsing)]
public async Task TestAddUsingWithLeadingDocCommentInFrontOfUsing1()
{
await TestAsync(
@"
/// Copyright 2016 - MyCompany
/// All Rights Reserved
using System;
class C : [|IEnumerable|]<int>
{
}
",
@"
/// Copyright 2016 - MyCompany
/// All Rights Reserved
using System;
using System.Collections.Generic;
class C : IEnumerable<int>
{
}
",
compareTokens: false);
}

[WorkItem(226826, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=226826")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddUsing)]
public async Task TestAddUsingWithLeadingDocCommentInFrontOfUsing2()
{
await TestAsync(
@"
/// Copyright 2016 - MyCompany
/// All Rights Reserved
using System.Collections;
class C
{
[|DateTime|] d;
}
",
@"
/// Copyright 2016 - MyCompany
/// All Rights Reserved
using System;
using System.Collections;
class C
{
DateTime d;
}
",
compareTokens: false);
}

[WorkItem(226826, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=226826")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddUsing)]
public async Task TestAddUsingWithLeadingDocCommentInFrontOfClass1()
{
await TestAsync(
@"
/// Copyright 2016 - MyCompany
/// All Rights Reserved
class C
{
[|DateTime|] d;
}
",
@"
using System;
/// Copyright 2016 - MyCompany
/// All Rights Reserved
class C
{
DateTime d;
}
",
compareTokens: false);
}

public partial class AddUsingTestsWithAddImportDiagnosticProvider : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,43 +125,58 @@ public static CompilationUnitSyntax AddUsingDirectives(

var usings = AddUsingDirectives(root, usingDirectives);

// If the user likes to have their Usings statements unsorted, allow them to
// Keep usings sorted if they were originally sorted.
if (root.Usings.IsSorted(comparer))
{
usings.Sort(comparer);
}

// If any using we added was moved to the first location, then take the trivia from
// the start of the first token and add it to the using we added. This way things
// like #define's and #r's will stay above the using.
var firstUsingChanged = root.Usings.Count == 0 || usings[0] != root.Usings[0];
if (firstUsingChanged && root.Externs.Count == 0)
if (root.Externs.Count == 0)
{
var firstToken = root.GetFirstToken();

// Move the leading directives from the first directive to the new using.
var firstUsing = usings[0].WithLeadingTrivia(firstToken.LeadingTrivia.Where(t => !t.IsDocComment() && !t.IsElastic()));

// Remove the leading directives from the first token.
var newFirstToken = firstToken.WithLeadingTrivia(firstToken.LeadingTrivia.Where(t => t.IsDocComment() || t.IsElastic()));

// Remove the leading trivia from the first token from the tree.
root = root.ReplaceToken(firstToken, newFirstToken);
if (root.Usings.Count == 0)
{
// We don't have any existing usings. Move any trivia on the first token
// of the file to the first using.
//
// Don't do this for doc comments, as they belong to the first element
// already in the file (like a class) and we don't want it to move to
// the using.
var firstToken = root.GetFirstToken();

// Remove the leading directives from the first token.
var newFirstToken = firstToken.WithLeadingTrivia(
firstToken.LeadingTrivia.Where(t => IsDocCommentOrElastic(t)));

root = root.ReplaceToken(firstToken, newFirstToken);

// Move the leading trivia from the first token to the first using.
var newFirstUsing = usings[0].WithLeadingTrivia(
firstToken.LeadingTrivia.Where(t => !IsDocCommentOrElastic(t)));
usings[0] = newFirstUsing;
}
else if (usings[0] != root.Usings[0])
{
// We added a new first-using. Take the trivia on the existing first using
// And move it to the new using.
var newFirstUsing = usings[0].WithLeadingTrivia(usings[1].GetLeadingTrivia())
.WithAppendedTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed);

// Create the new list of usings.
var finalUsings = new List<UsingDirectiveSyntax>();
finalUsings.Add(firstUsing);
finalUsings.AddRange(root.Usings);
finalUsings.AddRange(usingDirectives.Except(new[] { usings[0] }));
finalUsings.Sort(comparer);
usings = finalUsings;
usings[0] = newFirstUsing;
usings[1] = usings[1].WithoutLeadingTrivia();
}
}

usings = usings.Select(u => u.WithAdditionalAnnotations(annotations)).ToList();
return root.WithUsings(usings.ToSyntaxList());
return root.WithUsings(
usings.Select(u => u.WithAdditionalAnnotations(annotations)).ToSyntaxList());
}

private static bool IsDocCommentOrElastic(SyntaxTrivia t)
{
return t.IsDocComment() || t.IsElastic();
}

private static List<UsingDirectiveSyntax> AddUsingDirectives(CompilationUnitSyntax root, IList<UsingDirectiveSyntax> usingDirectives)
private static List<UsingDirectiveSyntax> AddUsingDirectives(
CompilationUnitSyntax root, IList<UsingDirectiveSyntax> usingDirectives)
{
// We need to try and not place the using inside of a directive if possible.
var usings = new List<UsingDirectiveSyntax>();
Expand Down

0 comments on commit e5ebda7

Please sign in to comment.