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

Unify code between C# and VB. #17824

Merged
merged 6 commits into from
Mar 14, 2017
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 @@ -309,11 +309,7 @@ private async Task<IEnumerable<CodeActionOperation>> GetGenerateInNewFileOperati
{
var syntaxFacts = _document.Document.GetLanguageService<ISyntaxFactsService>();
var fileBanner = syntaxFacts.GetFileBanner(_document.Root);

if (fileBanner.Any(syntaxFacts.IsRegularComment))
{
newRoot = newRoot.WithPrependedLeadingTrivia(fileBanner);
}
newRoot = newRoot.WithPrependedLeadingTrivia(fileBanner);
}

return await CreateAddDocumentAndUpdateUsingsOrImportsOperationsAsync(
Expand Down
164 changes: 13 additions & 151 deletions src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,50 +186,6 @@ public static NamespaceDeclarationSyntax GetInnermostNamespaceDeclarationWithUsi
}
}

// Matches the following:
//
// (whitespace* newline)+
private static readonly Matcher<SyntaxTrivia> s_oneOrMoreBlankLines;

// Matches the following:
//
// (whitespace* (single-comment|multi-comment) whitespace* newline)+ OneOrMoreBlankLines
private static readonly Matcher<SyntaxTrivia> s_bannerMatcher;

// Used to match the following:
//
// <start-of-file> (whitespace* (single-comment|multi-comment) whitespace* newline)+ blankLine*
private static readonly Matcher<SyntaxTrivia> s_fileBannerMatcher;

static SyntaxNodeExtensions()
{
var whitespace = Matcher.Repeat(Match(SyntaxKind.WhitespaceTrivia, "\\b"));
var endOfLine = Match(SyntaxKind.EndOfLineTrivia, "\\n");
var singleBlankLine = Matcher.Sequence(whitespace, endOfLine);

var shebangComment = Match(SyntaxKind.ShebangDirectiveTrivia, "#!");
var singleLineComment = Match(SyntaxKind.SingleLineCommentTrivia, "//");
var multiLineComment = Match(SyntaxKind.MultiLineCommentTrivia, "/**/");
var anyCommentMatcher = Matcher.Choice(shebangComment, singleLineComment, multiLineComment);

var commentLine = Matcher.Sequence(whitespace, anyCommentMatcher, whitespace, endOfLine);

s_oneOrMoreBlankLines = Matcher.OneOrMore(singleBlankLine);
s_bannerMatcher =
Matcher.Sequence(
Matcher.OneOrMore(commentLine),
s_oneOrMoreBlankLines);
s_fileBannerMatcher =
Matcher.Sequence(
Matcher.OneOrMore(commentLine),
Matcher.Repeat(singleBlankLine));
}

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)
Expand Down Expand Up @@ -559,120 +515,26 @@ public static IList<IList<TSyntaxNode>> SplitNodesOnPreprocessorBoundaries<TSynt
return result;
}

public static IEnumerable<SyntaxTrivia> GetLeadingBlankLines<TSyntaxNode>(
this TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
node.GetNodeWithoutLeadingBlankLines(out var blankLines);
return blankLines;
}

public static TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(
this TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
return node.GetNodeWithoutLeadingBlankLines(out var blankLines);
}

public static TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(
this TSyntaxNode node, out IEnumerable<SyntaxTrivia> strippedTrivia)
where TSyntaxNode : SyntaxNode
{
var leadingTriviaToKeep = new List<SyntaxTrivia>(node.GetLeadingTrivia());

var index = 0;
s_oneOrMoreBlankLines.TryMatch(leadingTriviaToKeep, ref index);

strippedTrivia = new List<SyntaxTrivia>(leadingTriviaToKeep.Take(index));

return node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index));
}

public static IEnumerable<SyntaxTrivia> GetLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(
this TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
node.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(out var leadingTrivia);
return leadingTrivia;
}

public static TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(
this TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
return node.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(out var strippedTrivia);
}

public static TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(
this TSyntaxNode node, out IEnumerable<SyntaxTrivia> strippedTrivia)
where TSyntaxNode : SyntaxNode
{
var leadingTrivia = node.GetLeadingTrivia();

// Rules for stripping trivia:
// 1) If there is a pp directive, then it (and all preceding trivia) *must* be stripped.
// This rule supersedes all other rules.
// 2) If there is a doc comment, it cannot be stripped. Even if there is a doc comment,
// followed by 5 new lines, then the doc comment still must stay with the node. This
// rule does *not* supersede rule 1.
// 3) Single line comments in a group (i.e. with no blank lines between them) belong to
// the node *iff* there is no blank line between it and the following trivia.

List<SyntaxTrivia> leadingTriviaToStrip, leadingTriviaToKeep;

int ppIndex = -1;
for (int i = leadingTrivia.Count - 1; i >= 0; i--)
{
if (SyntaxFacts.IsPreprocessorDirective(leadingTrivia[i].Kind()))
{
ppIndex = i;
break;
}
}

if (ppIndex != -1)
{
// We have a pp directive. it (and all previous trivia) must be stripped.
leadingTriviaToStrip = new List<SyntaxTrivia>(leadingTrivia.Take(ppIndex + 1));
leadingTriviaToKeep = new List<SyntaxTrivia>(leadingTrivia.Skip(ppIndex + 1));
}
else
{
leadingTriviaToKeep = new List<SyntaxTrivia>(leadingTrivia);
leadingTriviaToStrip = new List<SyntaxTrivia>();
}
public static ImmutableArray<SyntaxTrivia> GetLeadingBlankLines<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetLeadingBlankLines(node);

// Now, consume as many banners as we can. s_fileBannerMatcher will only be matched at
// the start of the file.
var index = 0;
while (
s_oneOrMoreBlankLines.TryMatch(leadingTriviaToKeep, ref index) ||
s_bannerMatcher.TryMatch(leadingTriviaToKeep, ref index) ||
(node.FullSpan.Start == 0 && s_fileBannerMatcher.TryMatch(leadingTriviaToKeep, ref index)))
{
}
public static TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBlankLines(node);

leadingTriviaToStrip.AddRange(leadingTriviaToKeep.Take(index));
public static TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(this TSyntaxNode node, out ImmutableArray<SyntaxTrivia> strippedTrivia) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBlankLines(node, out strippedTrivia);

strippedTrivia = leadingTriviaToStrip;
return node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index));
}

public static ImmutableArray<SyntaxTrivia> GetFileBanner(this SyntaxNode root)
{
Debug.Assert(root.FullSpan.Start == 0);
public static ImmutableArray<SyntaxTrivia> GetLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetLeadingBannerAndPreprocessorDirectives(node);

var leadingTrivia = root.GetLeadingTrivia();
var index = 0;
s_fileBannerMatcher.TryMatch(leadingTrivia.ToList(), ref index);
public static TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node);

return ImmutableArray.CreateRange(leadingTrivia.Take(index));
}
public static TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(this TSyntaxNode node, out ImmutableArray<SyntaxTrivia> strippedTrivia) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, out strippedTrivia);

public static bool IsAnyAssignExpression(this SyntaxNode node)
{
return SyntaxFacts.IsAssignmentExpression(node.Kind());
}
=> SyntaxFacts.IsAssignmentExpression(node.Kind());

public static bool IsCompoundAssignExpression(this SyntaxNode node)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,13 @@ public static bool IsRegularOrDocComment(this SyntaxTrivia trivia)
}

public static bool IsSingleLineComment(this SyntaxTrivia trivia)
{
return trivia.Kind() == SyntaxKind.SingleLineCommentTrivia;
}
=> trivia.Kind() == SyntaxKind.SingleLineCommentTrivia;

public static bool IsMultiLineComment(this SyntaxTrivia trivia)
{
return trivia.Kind() == SyntaxKind.MultiLineCommentTrivia;
}
=> trivia.Kind() == SyntaxKind.MultiLineCommentTrivia;

public static bool IsShebangDirective(this SyntaxTrivia trivia)
{
return trivia.Kind() == SyntaxKind.ShebangDirectiveTrivia;
}
=> trivia.Kind() == SyntaxKind.ShebangDirectiveTrivia;

public static bool IsCompleteMultiLineComment(this SyntaxTrivia trivia)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1029,9 +1029,7 @@ private string GetTypeName(TypeSyntax type)
}

private static string GetSimpleTypeName(SimpleNameSyntax name)
{
return name.Identifier.ValueText;
}
=> name.Identifier.ValueText;

private static string ExpandExplicitInterfaceName(string identifier, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifier)
{
Expand Down Expand Up @@ -1832,12 +1830,24 @@ public SyntaxNode GetOperandOfPrefixUnaryExpression(SyntaxNode node)
public SyntaxNode GetNextExecutableStatement(SyntaxNode statement)
=> ((StatementSyntax)statement).GetNextStatement();

public bool IsWhitespaceTrivia(SyntaxTrivia trivia)
public override bool IsWhitespaceTrivia(SyntaxTrivia trivia)
=> trivia.IsWhitespace();

public bool IsEndOfLineTrivia(SyntaxTrivia trivia)
public override bool IsEndOfLineTrivia(SyntaxTrivia trivia)
=> trivia.IsEndOfLine();

public override bool IsSingleLineCommentTrivia(SyntaxTrivia trivia)
=> trivia.IsSingleLineComment();

public override bool IsMultiLineCommentTrivia(SyntaxTrivia trivia)
=> trivia.IsMultiLineComment();

public override bool IsShebangDirectiveTrivia(SyntaxTrivia trivia)
=> trivia.IsShebangDirective();

public override bool IsPreprocessorDirective(SyntaxTrivia trivia)
=> SyntaxFacts.IsPreprocessorDirective(trivia.Kind());

private class AddFirstMissingCloseBaceRewriter: CSharpSyntaxRewriter
{
private readonly SyntaxNode _contextNode;
Expand Down Expand Up @@ -1979,8 +1989,5 @@ public bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int pos

public ImmutableArray<SyntaxNode> GetSelectedMembers(SyntaxNode root, TextSpan textSpan)
=> ImmutableArray<SyntaxNode>.CastUp(root.GetMembersInSpan(textSpan));

public ImmutableArray<SyntaxTrivia> GetFileBanner(SyntaxNode root)
=> root.GetFileBanner();
}
}
Loading