提交 18809c80 编写于 作者: C CyrusNajmabadi

Unify code between C# and VB.

上级 414fa9d7
......@@ -186,56 +186,30 @@ 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)
=> node.GetFirstToken().GetAllPrecedingTriviaToPreviousToken(
sourceText, includePreviousTokenTrailingTriviaOnlyIfOnSameLine);
public static ImmutableArray<SyntaxTrivia> GetLeadingBlankLines<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetLeadingBlankLines(node);
public static TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBlankLines(node);
public static TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(this TSyntaxNode node, out ImmutableArray<SyntaxTrivia> strippedTrivia) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBlankLines(node, out strippedTrivia);
public static ImmutableArray<SyntaxTrivia> GetLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetLeadingBannerAndPreprocessorDirectives(node);
public static TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(this TSyntaxNode node) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node);
public static TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(this TSyntaxNode node, out ImmutableArray<SyntaxTrivia> strippedTrivia) where TSyntaxNode : SyntaxNode
=> CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, out strippedTrivia);
/// <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).
......@@ -559,116 +533,6 @@ public static bool IsAnyLambdaOrAnonymousMethod(this SyntaxNode node)
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>();
}
// 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)))
{
}
leadingTriviaToStrip.AddRange(leadingTriviaToKeep.Take(index));
strippedTrivia = leadingTriviaToStrip;
return node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index));
}
public static ImmutableArray<SyntaxTrivia> GetFileBanner(this SyntaxNode root)
{
Debug.Assert(root.FullSpan.Start == 0);
var leadingTrivia = root.GetLeadingTrivia();
var index = 0;
s_fileBannerMatcher.TryMatch(leadingTrivia.ToList(), ref index);
return ImmutableArray.CreateRange(leadingTrivia.Take(index));
}
public static bool IsAnyAssignExpression(this SyntaxNode node)
{
return SyntaxFacts.IsAssignmentExpression(node.Kind());
......
......@@ -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)
{
......
......@@ -1832,12 +1832,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;
......@@ -1979,8 +1991,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();
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.LanguageServices
......@@ -17,6 +21,53 @@ internal abstract class AbstractSyntaxFactsService
private readonly static ObjectPool<Dictionary<string, string>> s_aliasMapPool =
new ObjectPool<Dictionary<string, string>>(() => new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
// Matches the following:
//
// (whitespace* newline)+
private readonly Matcher<SyntaxTrivia> _oneOrMoreBlankLines;
// Matches the following:
//
// (whitespace* (single-comment|multi-comment) whitespace* newline)+ OneOrMoreBlankLines
private readonly Matcher<SyntaxTrivia> _bannerMatcher;
// Used to match the following:
//
// <start-of-file> (whitespace* (single-comment|multi-comment) whitespace* newline)+ blankLine*
private readonly Matcher<SyntaxTrivia> _fileBannerMatcher;
protected AbstractSyntaxFactsService()
{
var whitespace = Matcher.Repeat(
Matcher.Single<SyntaxTrivia>(IsWhitespaceTrivia, "\\b"));
var endOfLine = Matcher.Single<SyntaxTrivia>(IsEndOfLineTrivia, "\\n");
var singleBlankLine = Matcher.Sequence(whitespace, endOfLine);
var shebangComment = Matcher.Single<SyntaxTrivia>(IsShebangDirectiveTrivia, "#!");
var singleLineComment = Matcher.Single<SyntaxTrivia>(IsSingleLineCommentTrivia, "//");
var multiLineComment = Matcher.Single<SyntaxTrivia>(IsMultiLineCommentTrivia, "/**/");
var anyCommentMatcher = Matcher.Choice(shebangComment, singleLineComment, multiLineComment);
var commentLine = Matcher.Sequence(whitespace, anyCommentMatcher, whitespace, endOfLine);
_oneOrMoreBlankLines = Matcher.OneOrMore(singleBlankLine);
_bannerMatcher =
Matcher.Sequence(
Matcher.OneOrMore(commentLine),
_oneOrMoreBlankLines);
_fileBannerMatcher =
Matcher.Sequence(
Matcher.OneOrMore(commentLine),
Matcher.Repeat(singleBlankLine));
}
public abstract bool IsWhitespaceTrivia(SyntaxTrivia trivia);
public abstract bool IsEndOfLineTrivia(SyntaxTrivia trivia);
public abstract bool IsSingleLineCommentTrivia(SyntaxTrivia trivia);
public abstract bool IsMultiLineCommentTrivia(SyntaxTrivia trivia);
public abstract bool IsShebangDirectiveTrivia(SyntaxTrivia trivia);
public abstract bool IsPreprocessorDirective(SyntaxTrivia trivia);
protected static List<Dictionary<string, string>> AllocateAliasMapList()
{
return s_aliasMapListPool.Allocate();
......@@ -47,5 +98,113 @@ protected static void FreeAliasMap(Dictionary<string, string> aliasMap)
{
return s_aliasMapPool.Allocate();
}
public ImmutableArray<SyntaxTrivia> GetLeadingBlankLines<TSyntaxNode>(TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
GetNodeWithoutLeadingBlankLines(node, out var blankLines);
return blankLines;
}
public TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
return GetNodeWithoutLeadingBlankLines(node, out var blankLines);
}
public TSyntaxNode GetNodeWithoutLeadingBlankLines<TSyntaxNode>(
TSyntaxNode node, out ImmutableArray<SyntaxTrivia> strippedTrivia)
where TSyntaxNode : SyntaxNode
{
var leadingTriviaToKeep = new List<SyntaxTrivia>(node.GetLeadingTrivia());
var index = 0;
_fileBannerMatcher.TryMatch(leadingTriviaToKeep, ref index);
strippedTrivia = leadingTriviaToKeep.Take(index).ToImmutableArray();
return node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index));
}
public ImmutableArray<SyntaxTrivia> GetLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, out var leadingTrivia);
return leadingTrivia;
}
public TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(
TSyntaxNode node)
where TSyntaxNode : SyntaxNode
{
return GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, out var strippedTrivia);
}
public TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives<TSyntaxNode>(
TSyntaxNode node, out ImmutableArray<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;
var ppIndex = -1;
for (var i = leadingTrivia.Count - 1; i >= 0; i--)
{
if (this.IsPreprocessorDirective(leadingTrivia[i]))
{
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>();
}
// Now, consume as many banners as we can. s_fileBannerMatcher will only be matched at
// the start of the file.
var index = 0;
while (
_oneOrMoreBlankLines.TryMatch(leadingTriviaToKeep, ref index) ||
_bannerMatcher.TryMatch(leadingTriviaToKeep, ref index) ||
(node.FullSpan.Start == 0 && _fileBannerMatcher.TryMatch(leadingTriviaToKeep, ref index)))
{
}
leadingTriviaToStrip.AddRange(leadingTriviaToKeep.Take(index));
strippedTrivia = leadingTriviaToStrip.ToImmutableArray();
return node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index));
}
public ImmutableArray<SyntaxTrivia> GetFileBanner(SyntaxNode root)
{
Debug.Assert(root.FullSpan.Start == 0);
var leadingTrivia = root.GetLeadingTrivia();
var index = 0;
_fileBannerMatcher.TryMatch(leadingTrivia.ToList(), ref index);
return ImmutableArray.CreateRange(leadingTrivia.Take(index));
}
}
}
}
\ No newline at end of file
......@@ -483,8 +483,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Dim statementArray = statements.OfType(Of StatementSyntax).ToArray()
Dim newBlock As SyntaxNode
If options.BeforeThisLocation IsNot Nothing Then
Dim strippedTrivia As IEnumerable(Of SyntaxTrivia) = Nothing
Dim newStatement = oldStatement.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(strippedTrivia)
Dim strippedTrivia As ImmutableArray(Of SyntaxTrivia) = Nothing
Dim newStatement = VisualBasicSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(
oldStatement, strippedTrivia)
statementArray(0) = statementArray(0).WithLeadingTrivia(strippedTrivia)
......
......@@ -188,44 +188,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
Return Contract.FailWithReturn(Of SyntaxList(Of StatementSyntax))("unknown statements container!")
End Function
' Matches the following:
'
' (whitespace* newline)+
Private ReadOnly s_oneOrMoreBlankLines As Matcher(Of SyntaxTrivia)
' Matches the following:
'
' (whitespace* comment whitespace* newline)+ OneOrMoreBlankLines
Private ReadOnly s_bannerMatcher As Matcher(Of SyntaxTrivia)
' Used to match the following:
'
' <start-of-file> (whitespace* comment whitespace* newline)+ blankLine*
Private ReadOnly s_fileBannerMatcher As Matcher(Of SyntaxTrivia)
Sub New()
Dim whitespace = Matcher.Repeat(Match(SyntaxKind.WhitespaceTrivia, "\\b"))
Dim endOfLine = Match(SyntaxKind.EndOfLineTrivia, "\\n")
Dim singleBlankLine = Matcher.Sequence(whitespace, endOfLine)
Dim comment = Match(SyntaxKind.CommentTrivia, "'")
Dim commentLine = Matcher.Sequence(whitespace, comment, 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))
End Sub
Private Function Match(kind As SyntaxKind, description As String) As Matcher(Of SyntaxTrivia)
Return Matcher.Single(Of SyntaxTrivia)(Function(t) t.Kind = kind, description)
End Function
<Extension()>
Friend Function IsMultiLineLambda(node As SyntaxNode) As Boolean
Return SyntaxFacts.IsMultiLineLambdaExpression(node.Kind())
......@@ -448,106 +410,34 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
Return False
End Function
<Extension()>
Public Function GetLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As IEnumerable(Of SyntaxTrivia)
Dim blankLines As IEnumerable(Of SyntaxTrivia) = Nothing
node.GetNodeWithoutLeadingBlankLines(blankLines)
Return blankLines
Public Function GetLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As ImmutableArray(Of SyntaxTrivia)
Return VisualBasicSyntaxFactsService.Instance.GetLeadingBlankLines(node)
End Function
<Extension()>
Public Function GetNodeWithoutLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As TSyntaxNode
Dim blankLines As IEnumerable(Of SyntaxTrivia) = Nothing
Return node.GetNodeWithoutLeadingBlankLines(blankLines)
Return VisualBasicSyntaxFactsService.Instance.GetNodeWithoutLeadingBlankLines(node)
End Function
<Extension()>
Public Function GetNodeWithoutLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(
node As TSyntaxNode, ByRef strippedTrivia As IEnumerable(Of SyntaxTrivia)) As TSyntaxNode
Dim leadingTriviaToKeep = New List(Of SyntaxTrivia)(node.GetLeadingTrivia())
Dim index = 0
s_oneOrMoreBlankLines.TryMatch(leadingTriviaToKeep, index)
strippedTrivia = New List(Of SyntaxTrivia)(leadingTriviaToKeep.Take(index))
Return DirectCast(node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index)), TSyntaxNode)
Public Function GetNodeWithoutLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode, ByRef strippedTrivia As ImmutableArray(Of SyntaxTrivia)) As TSyntaxNode
Return VisualBasicSyntaxFactsService.Instance.GetNodeWithoutLeadingBlankLines(node, strippedTrivia)
End Function
<Extension()>
Public Function GetLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As IEnumerable(Of SyntaxTrivia)
Dim leadingTrivia As IEnumerable(Of SyntaxTrivia) = Nothing
node.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(leadingTrivia)
Return leadingTrivia
Public Function GetLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As ImmutableArray(Of SyntaxTrivia)
Return VisualBasicSyntaxFactsService.Instance.GetLeadingBannerAndPreprocessorDirectives(node)
End Function
<Extension()>
Public Function GetNodeWithoutLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As TSyntaxNode
Dim strippedTrivia As IEnumerable(Of SyntaxTrivia) = Nothing
Return node.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(strippedTrivia)
Return VisualBasicSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node)
End Function
<Extension()>
Public Function GetNodeWithoutLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(
node As TSyntaxNode,
ByRef strippedTrivia As IEnumerable(Of SyntaxTrivia)) As TSyntaxNode
Dim 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.
Dim leadingTriviaToStrip, leadingTriviaToKeep As List(Of SyntaxTrivia)
Dim ppIndex = -1
For i = leadingTrivia.Count - 1 To 0 Step -1
If SyntaxFacts.IsPreprocessorDirective(leadingTrivia(i).Kind) Then
ppIndex = i
Exit For
End If
Next
If ppIndex <> -1 Then
' We have a pp directive. it (and all previous trivia) must be stripped.
leadingTriviaToStrip = New List(Of SyntaxTrivia)(leadingTrivia.Take(ppIndex + 1))
leadingTriviaToKeep = New List(Of SyntaxTrivia)(leadingTrivia.Skip(ppIndex + 1))
Else
leadingTriviaToKeep = New List(Of SyntaxTrivia)(leadingTrivia)
leadingTriviaToStrip = New List(Of SyntaxTrivia)()
End If
' Now, consume as many banners as we can. s_fileBannerMatcher will only be matched at
' the start of the file.
Dim index = 0
While (
s_oneOrMoreBlankLines.TryMatch(leadingTriviaToKeep, index) OrElse
s_bannerMatcher.TryMatch(leadingTriviaToKeep, index) OrElse
(node.FullSpan.Start = 0 AndAlso s_fileBannerMatcher.TryMatch(leadingTriviaToKeep, index)))
End While
leadingTriviaToStrip.AddRange(leadingTriviaToKeep.Take(index))
strippedTrivia = leadingTriviaToStrip
Return DirectCast(node.WithLeadingTrivia(leadingTriviaToKeep.Skip(index)), TSyntaxNode)
End Function
<Extension>
Public Function GetFileBanner(root As SyntaxNode) As ImmutableArray(Of SyntaxTrivia)
Debug.Assert(root.FullSpan.Start = 0)
Dim leadingTrivia = root.GetLeadingTrivia()
Dim index = 0
s_fileBannerMatcher.TryMatch(leadingTrivia.ToList(), index)
Return ImmutableArray.CreateRange(leadingTrivia.Take(index))
Public Function GetNodeWithoutLeadingBannerAndPreprocessorDirectives(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode, ByRef strippedTrivia As ImmutableArray(Of SyntaxTrivia)) As TSyntaxNode
Return VisualBasicSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, strippedTrivia)
End Function
''' <summary>
......
......@@ -1659,14 +1659,32 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return DirectCast(statement, StatementSyntax).GetNextStatement()?.FirstAncestorOrSelf(Of ExecutableStatementSyntax)
End Function
Public Function IsWhitespaceTrivia(trivia As SyntaxTrivia) As Boolean Implements ISyntaxFactsService.IsWhitespaceTrivia
Public Overrides Function IsWhitespaceTrivia(trivia As SyntaxTrivia) As Boolean Implements ISyntaxFactsService.IsWhitespaceTrivia
Return trivia.IsWhitespace()
End Function
Public Function IsEndOfLineTrivia(trivia As SyntaxTrivia) As Boolean Implements ISyntaxFactsService.IsEndOfLineTrivia
Public Overrides Function IsEndOfLineTrivia(trivia As SyntaxTrivia) As Boolean Implements ISyntaxFactsService.IsEndOfLineTrivia
Return trivia.IsEndOfLine()
End Function
Public Overrides Function IsSingleLineCommentTrivia(trivia As SyntaxTrivia) As Boolean
Return trivia.Kind = SyntaxKind.CommentTrivia
End Function
Public Overrides Function IsMultiLineCommentTrivia(trivia As SyntaxTrivia) As Boolean
' VB does not have multi-line comments.
Return False
End Function
Public Overrides Function IsShebangDirectiveTrivia(trivia As SyntaxTrivia) As Boolean
' VB does not have shebang directives.
Return False
End Function
Public Overrides Function IsPreprocessorDirective(trivia As SyntaxTrivia) As Boolean
Return SyntaxFacts.IsPreprocessorDirective(trivia.Kind())
End Function
Public Function IsRegularComment(trivia As SyntaxTrivia) As Boolean Implements ISyntaxFactsService.IsRegularComment
Return trivia.Kind = SyntaxKind.CommentTrivia
End Function
......@@ -1734,8 +1752,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return ImmutableArray(Of SyntaxNode).CastUp(root.GetMembersInSpan(textSpan))
End Function
Public Function GetFileBanner(root As SyntaxNode) As ImmutableArray(Of SyntaxTrivia) Implements ISyntaxFactsService.GetFileBanner
Return root.GetFileBanner()
Private Function ISyntaxFactsService_GetFileBanner(root As SyntaxNode) As ImmutableArray(Of SyntaxTrivia) Implements ISyntaxFactsService.GetFileBanner
Return GetFileBanner(root)
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -2,6 +2,7 @@
Imports System
Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports System.Globalization
Imports System.Linq
Imports System.Text
......@@ -16,7 +17,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.VisualBasic.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.Utilities
Friend Partial Class ImportsOrganizer
Partial Friend Class ImportsOrganizer
Public Shared Function Organize([imports] As SyntaxList(Of ImportsStatementSyntax),
placeSystemNamespaceFirst As Boolean) As SyntaxList(Of ImportsStatementSyntax)
If [imports].Count > 1 Then
......@@ -24,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Utilities
If Not [imports].SpansPreprocessorDirective() Then
' If there is a banner comment that precedes the nodes,
' then remove it and store it for later.
Dim leadingTrivia As IEnumerable(Of SyntaxTrivia) = Nothing
Dim leadingTrivia As ImmutableArray(Of SyntaxTrivia) = Nothing
initialList(0) = initialList(0).GetNodeWithoutLeadingBannerAndPreprocessorDirectives(leadingTrivia)
Dim comparer = If(placeSystemNamespaceFirst, ImportsStatementComparer.SystemFirstInstance, ImportsStatementComparer.NormalInstance)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册