' Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax
Friend Class SyntaxFormatter
Inherits VisualBasicSyntaxRewriter
Private ReadOnly indentWhitespace As String
Private ReadOnly useElasticTrivia As Boolean
Private ReadOnly useDefaultCasing As Boolean
Private isInStructuredTrivia As Boolean
Private previousToken As SyntaxToken
Private afterLineBreak As Boolean
Private afterIndentation As Boolean
Private lineBreaksAfterToken As Dictionary(Of SyntaxToken, Integer) = New Dictionary(Of SyntaxToken, Integer)()
Private lastStatementsInBlocks As HashSet(Of SyntaxNode) = New HashSet(Of SyntaxNode)()
Private indentationDepth As Integer
Private indentations As ArrayBuilder(Of SyntaxTrivia)
'''
''' Creates a Syntax Formatter visitor
'''
''' The whitespace to indent with
''' Whether to use elastic trivia or not
''' Whether to rewrite keywords in default casing or not
'''
Private Sub New(indentWhitespace As String, Optional useElasticTrivia As Boolean = False, Optional useDefaultCasing As Boolean = False)
: MyBase.New(VisitIntoStructuredTrivia:=True)
Me.indentWhitespace = indentWhitespace
Me.useElasticTrivia = useElasticTrivia
Me.useDefaultCasing = useDefaultCasing
Me.afterLineBreak = True
End Sub
Friend Shared Function Format(Of TNode As SyntaxNode)(node As TNode, indentWhitespace As String, Optional useElasticTrivia As Boolean = False, Optional useDefaultCasing As Boolean = False) As SyntaxNode
Dim formatter As New SyntaxFormatter(indentWhitespace, useElasticTrivia, useDefaultCasing)
Dim result As TNode = CType(formatter.Visit(node), TNode)
formatter.Free()
Return result
End Function
Friend Shared Function Format(token As SyntaxToken, indentWhitespace As String, Optional useElasticTrivia As Boolean = False, Optional useDefaultCasing As Boolean = False) As SyntaxToken
Dim formatter As New SyntaxFormatter(indentWhitespace, useElasticTrivia, useDefaultCasing)
Dim result As SyntaxToken = formatter.VisitToken(token)
formatter.Free()
Return result
End Function
Friend Shared Function Format(trivia As SyntaxTriviaList, indentWhitespace As String, Optional useElasticTrivia As Boolean = False, Optional useDefaultCasing As Boolean = False) As SyntaxTriviaList
Dim formatter = New SyntaxFormatter(indentWhitespace, useElasticTrivia, useDefaultCasing)
Dim result As SyntaxTriviaList = formatter.RewriteTrivia(trivia,
formatter.GetIndentationDepth(),
isTrailing:=False,
mustBeIndented:=False,
mustHaveSeparator:=False,
lineBreaksAfter:=0, lineBreaksBefore:=0)
formatter.Free()
Return result
End Function
Private Sub Free()
If indentations IsNot Nothing Then
indentations.Free()
End If
End Sub
Private Function GetIdentation(count As Integer) As SyntaxTrivia
Dim capacity = count + 1
If indentations Is Nothing Then
indentations = ArrayBuilder(Of SyntaxTrivia).GetInstance(capacity)
Else
indentations.EnsureCapacity(capacity)
End If
For i As Integer = indentations.Count To count
Dim text As String = If(i = 0, "", indentations(i - 1).ToString() + Me.indentWhitespace)
indentations.Add(SyntaxFactory.Whitespace(text, Me.useElasticTrivia))
Next
Return indentations(count)
End Function
' use leadingTrivia as indentation
' use trailingTrivia as separation & newlines if needed
Public Overrides Function VisitToken(token As SyntaxToken) As SyntaxToken
' ignore tokens with no content
If token.VisualBasicKind = SyntaxKind.None Then
Return token
End If
Try
Dim newToken As SyntaxToken
If useDefaultCasing AndAlso IsKeyword(token) Then
newToken = SyntaxFactory.Token(token.VisualBasicKind)
Else
newToken = token
End If
Dim indentationDepth = GetIndentationDepth()
' check if this token is first on this line
Dim numLineBreaksBefore As Integer = LineBreaksBetween(previousToken, token)
Dim needsIndentation As Boolean = (numLineBreaksBefore > 0)
' all line breaks except the first will be leading trivia of this token. The first line break
' is trailing trivia of the previous token.
If numLineBreaksBefore > 0 AndAlso IsLastTokenOnLine(previousToken) Then
numLineBreaksBefore -= 1
End If
newToken = newToken.WithLeadingTrivia(
RewriteTrivia(
token.LeadingTrivia,
indentationDepth,
isTrailing:=False,
mustBeIndented:=needsIndentation,
mustHaveSeparator:=False,
lineBreaksAfter:=0,
lineBreaksBefore:=numLineBreaksBefore))
Dim nextToken As SyntaxToken = GetNextRelevantToken(token)
Me.afterIndentation = False
' we only add one of the line breaks to trivia of this token. The remaining ones will be leading trivia
' for the next token
Dim numLineBreaksAfter As Integer = If(LineBreaksBetween(token, nextToken) > 0, 1, 0)
Dim needsSeparatorAfter = If(numLineBreaksAfter > 0, False, NeedsSeparator(token, nextToken))
newToken = newToken.WithTrailingTrivia(
RewriteTrivia(
token.TrailingTrivia,
depth:=0,
isTrailing:=True,
mustBeIndented:=False,
mustHaveSeparator:=needsSeparatorAfter,
lineBreaksAfter:=numLineBreaksAfter,
lineBreaksBefore:=0))
If newToken.VisualBasicKind = SyntaxKind.DocumentationCommentLineBreakToken Then
afterLineBreak = True
ElseIf newToken.VisualBasicKind = SyntaxKind.XmlTextLiteralToken Then
If newToken.TrailingTrivia.Count = 0 AndAlso IsNewLineChar(newToken.ValueText.Last) Then
afterLineBreak = True
End If
End If
Return newToken
Finally
Me.previousToken = token
End Try
Return token
End Function
Private Function RewriteTrivia(
triviaList As SyntaxTriviaList,
depth As Integer,
isTrailing As Boolean,
mustBeIndented As Boolean,
mustHaveSeparator As Boolean,
lineBreaksAfter As Integer,
lineBreaksBefore As Integer) As SyntaxTriviaList
Dim currentTriviaList As ArrayBuilder(Of SyntaxTrivia) = ArrayBuilder(Of SyntaxTrivia).GetInstance()
Try
For i = 1 To lineBreaksBefore
currentTriviaList.Add(GetCarriageReturnLineFeed())
afterLineBreak = True
afterIndentation = False
Next
For Each trivia In triviaList
' just keep non whitespace trivia
If trivia.VisualBasicKind = SyntaxKind.WhitespaceTrivia OrElse
trivia.VisualBasicKind = SyntaxKind.EndOfLineTrivia OrElse
trivia.VisualBasicKind = SyntaxKind.LineContinuationTrivia OrElse
trivia.FullWidth = 0 Then
Continue For
End If
' check if there's a separator or a line break needed between the trivia itself
Dim tokenParent = trivia.Token.Parent
Dim needsSeparator As Boolean =
Not (trivia.VisualBasicKind = SyntaxKind.ColonTrivia AndAlso tokenParent IsNot Nothing AndAlso tokenParent.VisualBasicKind = SyntaxKind.LabelStatement) AndAlso
Not (tokenParent IsNot Nothing AndAlso tokenParent.Parent IsNot Nothing AndAlso tokenParent.Parent.VisualBasicKind = SyntaxKind.CrefReference) AndAlso
(
(currentTriviaList.Count > 0 AndAlso NeedsSeparatorBetween(currentTriviaList.Last()) AndAlso Not EndsInLineBreak(currentTriviaList.Last())) OrElse
(currentTriviaList.Count = 0 AndAlso isTrailing)
)
Dim needsLineBreak As Boolean = NeedsLineBreakBefore(trivia) OrElse
(currentTriviaList.Count > 0 AndAlso NeedsLineBreakBetween(currentTriviaList.Last(), trivia, isTrailing))
If needsLineBreak AndAlso Not afterLineBreak Then
currentTriviaList.Add(GetCarriageReturnLineFeed())
afterLineBreak = True
afterIndentation = False
End If
If afterLineBreak And Not isTrailing Then
If Not afterIndentation AndAlso Me.NeedsIndentAfterLineBreak(trivia) Then
currentTriviaList.Add(Me.GetIdentation(GetIndentationDepth(trivia)))
afterIndentation = True
End If
ElseIf needsSeparator Then
currentTriviaList.Add(GetSpace())
afterLineBreak = False
afterIndentation = False
End If
If trivia.HasStructure Then
Dim structuredTrivia As SyntaxTrivia = Me.VisitStructuredTrivia(trivia)
currentTriviaList.Add(structuredTrivia)
Else
' in structured trivia, the xml doc ''' token contains leading whitespace as text (*yiiks*)
If trivia.VisualBasicKind = SyntaxKind.DocumentationCommentExteriorTrivia Then
trivia = SyntaxFactory.DocumentationCommentExteriorTrivia(SyntaxFacts.GetText(SyntaxKind.DocumentationCommentExteriorTrivia))
End If
currentTriviaList.Add(trivia)
End If
If NeedsLineBreakAfter(trivia) Then
If Not isTrailing Then
currentTriviaList.Add(GetCarriageReturnLineFeed())
afterLineBreak = True
afterIndentation = False
End If
Else
afterLineBreak = EndsInLineBreak(trivia)
End If
Next
If lineBreaksAfter > 0 Then
If currentTriviaList.Count > 0 AndAlso EndsInLineBreak(currentTriviaList.Last()) Then
lineBreaksAfter = lineBreaksAfter - 1
End If
For i = 0 To lineBreaksAfter - 1
currentTriviaList.Add(GetCarriageReturnLineFeed())
afterLineBreak = True
afterIndentation = False
Next i
ElseIf mustHaveSeparator Then
currentTriviaList.Add(GetSpace())
afterLineBreak = False
afterIndentation = False
End If
If mustBeIndented Then
currentTriviaList.Add(Me.GetIdentation(depth))
afterIndentation = True
afterLineBreak = False
End If
If currentTriviaList.Count = 0 Then
If useElasticTrivia Then
Return SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker)
Else
Return Nothing
End If
ElseIf currentTriviaList.Count = 1 Then
Return SyntaxFactory.TriviaList(currentTriviaList.First())
Else
Return SyntaxFactory.TriviaList(currentTriviaList)
End If
Finally
currentTriviaList.Free()
End Try
End Function
Private Function IsLastTokenOnLine(token As SyntaxToken) As Boolean
Return (token.HasTrailingTrivia AndAlso token.TrailingTrivia.Last.VisualBasicKind = SyntaxKind.ColonTrivia) OrElse
(token.Parent IsNot Nothing AndAlso token.Parent.GetLastToken() = token)
End Function
Private Function LineBreaksBetween(currentToken As SyntaxToken, nextToken As SyntaxToken) As Integer
' First and last token may be of kind none
If currentToken.VisualBasicKind = SyntaxKind.None OrElse nextToken.VisualBasicKind = SyntaxKind.None Then
Return 0
End If
Dim numLineBreaks As Integer = 0
If lineBreaksAfterToken.TryGetValue(currentToken, numLineBreaks) Then
Return numLineBreaks
End If
Return 0
End Function
'''
''' indentation depth is the declaration depth for statements within the block. for start/end statements
''' of these blocks (e.g. the if statement), it is a level less
'''
Private Function GetIndentationDepth() As Integer
Debug.Assert(Me.indentationDepth >= 0)
Return Me.indentationDepth
End Function
Private Function GetIndentationDepth(trivia As SyntaxTrivia) As Integer
If SyntaxFacts.IsPreprocessorDirective(trivia.VisualBasicKind) Then
Return 0
End If
Return GetIndentationDepth()
End Function
Private Function GetSpace() As SyntaxTrivia
Return If(Me.useElasticTrivia, SyntaxFactory.ElasticSpace, SyntaxFactory.Space)
End Function
Private Function GetCarriageReturnLineFeed() As SyntaxTrivia
Return If(Me.useElasticTrivia, SyntaxFactory.ElasticCarriageReturnLineFeed, SyntaxFactory.CarriageReturnLineFeed)
End Function
Private Function NeedsSeparatorBetween(trivia As SyntaxTrivia) As Boolean
Select Case trivia.VisualBasicKind
Case SyntaxKind.None,
SyntaxKind.WhitespaceTrivia,
SyntaxKind.DocumentationCommentExteriorTrivia,
SyntaxKind.LineContinuationTrivia
Return False
Case Else
Return Not SyntaxFacts.IsPreprocessorDirective(trivia.VisualBasicKind)
End Select
End Function
Private Function NeedsLineBreakBetween(trivia As SyntaxTrivia, nextTrivia As SyntaxTrivia, isTrailingTrivia As Boolean) As Boolean
If EndsInLineBreak(trivia) Then
Return False
End If
Select Case nextTrivia.VisualBasicKind
Case SyntaxKind.CommentTrivia, SyntaxKind.DocumentationCommentExteriorTrivia, SyntaxKind.EmptyStatement,
SyntaxKind.IfDirectiveTrivia,
SyntaxKind.ElseIfDirectiveTrivia,
SyntaxKind.ElseDirectiveTrivia,
SyntaxKind.EndIfDirectiveTrivia,
SyntaxKind.RegionDirectiveTrivia,
SyntaxKind.EndRegionDirectiveTrivia,
SyntaxKind.ConstDirectiveTrivia,
SyntaxKind.ExternalSourceDirectiveTrivia,
SyntaxKind.EndExternalSourceDirectiveTrivia,
SyntaxKind.ExternalChecksumDirectiveTrivia,
SyntaxKind.ReferenceDirectiveTrivia,
SyntaxKind.BadDirectiveTrivia
Return Not isTrailingTrivia
Case Else
Return False
End Select
End Function
Private Function NeedsLineBreakAfter(trivia As SyntaxTrivia) As Boolean
Return trivia.VisualBasicKind = SyntaxKind.CommentTrivia
End Function
Private Function NeedsLineBreakBefore(trivia As SyntaxTrivia) As Boolean
Select Case trivia.VisualBasicKind
Case SyntaxKind.DocumentationCommentExteriorTrivia
Return True
Case Else
Return False
End Select
End Function
Private Function NeedsIndentAfterLineBreak(trivia As SyntaxTrivia) As Boolean
Select Case trivia.VisualBasicKind
Case SyntaxKind.CommentTrivia,
SyntaxKind.DocumentationCommentExteriorTrivia,
SyntaxKind.DocumentationCommentTrivia
Return True
Case Else
Return False
End Select
End Function
Private Function NeedsSeparator(token As SyntaxToken, nextToken As SyntaxToken) As Boolean
If token.VisualBasicKind = SyntaxKind.EndOfFileToken Then
Return False
End If
If token.Parent Is Nothing OrElse nextToken.VisualBasicKind = SyntaxKind.None Then
Return False
End If
If nextToken.Parent.VisualBasicKind = SyntaxKind.SingleLineFunctionLambdaExpression Then
Return True
End If
If nextToken.VisualBasicKind = SyntaxKind.EndOfFileToken Then
Return False
End If
' +1 instead of + 1
' but not a instead of nota ...
If TypeOf (token.Parent) Is UnaryExpressionSyntax AndAlso
token.VisualBasicKind <> SyntaxKind.NotKeyword AndAlso
token.VisualBasicKind <> SyntaxKind.AddressOfKeyword Then
Return False
End If
' generally a + b, needs to go here to make it b + (a + b) instead of b +(a + b
If TypeOf (token.Parent) Is BinaryExpressionSyntax OrElse
TypeOf (nextToken.Parent) Is BinaryExpressionSyntax Then
Return True
End If
' (a instead of ( a
If token.VisualBasicKind = SyntaxKind.OpenParenToken Then
Return False
End If
' a) instead of a )
If nextToken.VisualBasicKind = SyntaxKind.CloseParenToken Then
Return False
End If
' m( instead of m (
If token.VisualBasicKind <> SyntaxKind.CommaToken AndAlso nextToken.VisualBasicKind = SyntaxKind.OpenParenToken Then
Return False
End If
' (,,,) instead of ( , , ,) or (a As Char, b as Char) instead of (a As Char , b as Char)
If (token.VisualBasicKind = SyntaxKind.CommaToken AndAlso nextToken.VisualBasicKind = SyntaxKind.EmptyToken) OrElse
nextToken.VisualBasicKind = SyntaxKind.CommaToken Then
Return False
End If
' a.b and .b instead of a . b, but keep with {key .field}
If token.VisualBasicKind = SyntaxKind.DotToken Then
Return False
ElseIf nextToken.VisualBasicKind = SyntaxKind.DotToken AndAlso nextToken.Parent.VisualBasicKind <> SyntaxKind.NamedFieldInitializer Then
Return False
End If
' label: instead of label :
If nextToken.VisualBasicKind = SyntaxKind.ColonToken AndAlso token.Parent.VisualBasicKind = SyntaxKind.LabelStatement Then
Return False
End If
' {1 instead of { 1 and 1} instead of 1 }
If token.VisualBasicKind = SyntaxKind.OpenBraceToken OrElse nextToken.VisualBasicKind = SyntaxKind.CloseBraceToken Then
Return False
End If
' s1(p1:=23, p2:=12) instead of s1(p1 := 23, p2 := 12)
If token.VisualBasicKind = SyntaxKind.ColonEqualsToken OrElse nextToken.VisualBasicKind = SyntaxKind.ColonEqualsToken Then
Return False
End If
' case > 100 should keep separator
' need to test before xml analysis below
If SyntaxFacts.IsRelationalCaseClause(token.Parent.VisualBasicKind()) OrElse
SyntaxFacts.IsRelationalCaseClause(nextToken.Parent.VisualBasicKind()) Then
Return True
End If
' handle closing attribute before XML tokens
' sub foo( ByRef i as Integer) instead of sub foo(ByRef i as Integer)
If (token.VisualBasicKind = SyntaxKind.GreaterThanToken AndAlso
token.Parent.VisualBasicKind = SyntaxKind.AttributeList) Then
Return True
End If
' needs to be checked after binary operators
' Imports instead of
If nextToken.VisualBasicKind = SyntaxKind.SlashGreaterThanToken Then
Return False
End If
' instead of
If token.VisualBasicKind = SyntaxKind.LessThanExclamationMinusMinusToken OrElse
nextToken.VisualBasicKind = SyntaxKind.MinusMinusGreaterThanToken Then
Return False
End If
' instead of xml ?>
If token.VisualBasicKind = SyntaxKind.LessThanQuestionToken Then
Return False
End If
' instead of
If token.VisualBasicKind = SyntaxKind.BeginCDataToken OrElse
nextToken.VisualBasicKind = SyntaxKind.EndCDataToken Then
Return False
End If
' instead of
If token.VisualBasicKind = SyntaxKind.ColonToken AndAlso token.Parent.VisualBasicKind = SyntaxKind.AttributeTarget OrElse
nextToken.VisualBasicKind = SyntaxKind.ColonToken AndAlso nextToken.Parent.VisualBasicKind = SyntaxKind.AttributeTarget Then
Return False
End If
' @a instead of @ a
If token.VisualBasicKind = SyntaxKind.AtToken AndAlso token.Parent.VisualBasicKind = SyntaxKind.XmlAttributeAccessExpression Then
Return False
End If
' 'e' instead of ' e '
If token.VisualBasicKind = SyntaxKind.SingleQuoteToken OrElse
nextToken.VisualBasicKind = SyntaxKind.SingleQuoteToken Then
Return False
End If
' Integer? instead of Integer ?
If nextToken.VisualBasicKind = SyntaxKind.QuestionToken Then
Return False
End If
' #if instead of # if
If token.VisualBasicKind = SyntaxKind.HashToken AndAlso TypeOf token.Parent Is DirectiveTriviaSyntax Then
Return False
End If
' "#region" instead of "#region "
If token.Parent.VisualBasicKind = SyntaxKind.RegionDirectiveTrivia AndAlso
nextToken.VisualBasicKind = SyntaxKind.StringLiteralToken AndAlso
String.IsNullOrEmpty(nextToken.ValueText) Then
Return False
End If
If token.VisualBasicKind = SyntaxKind.XmlTextLiteralToken OrElse token.VisualBasicKind = SyntaxKind.DocumentationCommentLineBreakToken Then
Return False
End If
Return True
End Function
Private Function EndsInLineBreak(trivia As SyntaxTrivia) As Boolean
If trivia.VisualBasicKind = SyntaxKind.EndOfLineTrivia Then
Return True
End If
If trivia.VisualBasicKind = SyntaxKind.DisabledTextTrivia Then
Dim text As String = trivia.ToFullString()
Return text.Length > 0 AndAlso IsNewLineChar(text.Last())
End If
If trivia.HasStructure Then
If trivia.GetStructure.GetLastToken.HasTrailingTrivia AndAlso
trivia.GetStructure.GetLastToken.TrailingTrivia.Last.VisualBasicKind = SyntaxKind.EndOfLineTrivia Then
Return True
End If
End If
Return False
End Function
Private Shared Function IsNewLineChar(ch As Char) As Boolean
' new-line-character:
' Carriage return character (U+000D)
' Line feed character (U+000A)
' Next line character (U+0085)
' Line separator character (U+2028)
' Paragraph separator character (U+2029)
Return ch = vbLf _
OrElse ch = vbCr _
OrElse ch = "\u0085" _
OrElse ch = "\u2028" _
OrElse ch = "\u2029"
End Function
Private Function IsKeyword(token As SyntaxToken) As Boolean
Return token.IsReservedKeyword() OrElse SyntaxFacts.IsPreprocessorDirective(token.VisualBasicKind)
End Function
Private Overloads Function VisitStructuredTrivia(trivia As SyntaxTrivia) As SyntaxTrivia
Dim oldIsInStructuredTrivia As Boolean = Me.isInStructuredTrivia
Me.isInStructuredTrivia = True
Dim oldPreviousToken = Me.previousToken
Me.previousToken = Nothing
Dim result As SyntaxTrivia = VisitTrivia(trivia)
Me.isInStructuredTrivia = oldIsInStructuredTrivia
Me.previousToken = oldPreviousToken
Return result
End Function
Private Function GetNextRelevantToken(token As SyntaxToken) As SyntaxToken
Return token.GetNextToken(Function(t As SyntaxToken)
Return t.VisualBasicKind <> SyntaxKind.None
End Function, Function(t As SyntaxTrivia) False)
End Function
Private Sub AddLinebreaksAfterElementsIfNeeded(Of TNode As SyntaxNode)(
list As SyntaxList(Of TNode),
linebreaksBetweenElements As Integer,
linebreaksAfterLastElement As Integer
)
Dim lastElementIndex = list.Count - 1
For elementIndex = 0 To lastElementIndex
Dim listElement = list(elementIndex)
If listElement.VisualBasicKind = SyntaxKind.LabelStatement Then
' always add linebreaks after label
lineBreaksAfterToken(listElement.GetLastToken()) = 1
Else
AddLinebreaksAfterTokenIfNeeded(listElement.GetLastToken(), If(elementIndex = lastElementIndex,
linebreaksAfterLastElement,
linebreaksBetweenElements))
End If
Next
End Sub
Private Sub AddLinebreaksAfterTokenIfNeeded(node As SyntaxToken, linebreaksAfterToken As Integer)
If Not EndsWithColonSeparator(node) Then
Me.lineBreaksAfterToken(node) = linebreaksAfterToken
End If
End Sub
Private Function EndsWithColonSeparator(node As SyntaxToken) As Boolean
Return node.HasTrailingTrivia AndAlso
node.TrailingTrivia.Last.VisualBasicKind = SyntaxKind.ColonTrivia
End Function
Private Sub MarkLastStatementIfNeeded(Of TNode As SyntaxNode)(list As SyntaxList(Of TNode))
If list.Any Then
lastStatementsInBlocks.Add(list.Last)
End If
End Sub
'''
''' We each element of option, imports and attributes on a separate line, where the last element of this the list if
''' followed by an empty line:
''' Option Strict On
'''
''' Imports System
''' Imports Foo
'''
''' [...]
'''
''' Namespace
''' [...]
'''
Public Overrides Function VisitCompilationUnit(node As CompilationUnitSyntax) As SyntaxNode
Dim hasImports = node.Imports.Any
Dim hasMembers = node.Members.Any
Dim hasAttributes = node.Attributes.Any
If hasImports OrElse hasAttributes OrElse hasMembers Then
AddLinebreaksAfterElementsIfNeeded(node.Options, 1, 2)
Else
AddLinebreaksAfterElementsIfNeeded(node.Options, 1, 1)
End If
If hasAttributes OrElse hasMembers Then
AddLinebreaksAfterElementsIfNeeded(node.Imports, 1, 2)
Else
AddLinebreaksAfterElementsIfNeeded(node.Imports, 1, 1)
End If
If hasMembers Then
AddLinebreaksAfterElementsIfNeeded(node.Attributes, 1, 2)
Else
AddLinebreaksAfterElementsIfNeeded(node.Attributes, 1, 1)
End If
AddLinebreaksAfterElementsIfNeeded(node.Members, 2, 1)
Return MyBase.VisitCompilationUnit(node)
End Function
'''
''' Add an empty line after the begin, except the first member is a nested namespace.
''' Separate each member of a namespace with an empty line.
'''
Public Overrides Function VisitNamespaceBlock(node As NamespaceBlockSyntax) As SyntaxNode
If node.Members.Count > 0 Then
' Add an empty line after the namespace begin if there
' is not a namespace declaration as first member
If node.Members(0).Kind <> SyntaxKind.NamespaceBlock Then
AddLinebreaksAfterTokenIfNeeded(node.NamespaceStatement.GetLastToken(), 2)
Else
AddLinebreaksAfterTokenIfNeeded(node.NamespaceStatement.GetLastToken(), 1)
End If
AddLinebreaksAfterElementsIfNeeded(node.Members, 2, 1)
Else
AddLinebreaksAfterTokenIfNeeded(node.NamespaceStatement.GetLastToken(), 1)
End If
Return MyBase.VisitNamespaceBlock(node)
End Function
Public Overrides Function VisitModuleBlock(ByVal node As ModuleBlockSyntax) As SyntaxNode
VisitTypeBlockSyntax(node)
Return MyBase.VisitModuleBlock(node)
End Function
Public Overrides Function VisitClassBlock(ByVal node As ClassBlockSyntax) As SyntaxNode
VisitTypeBlockSyntax(node)
Return MyBase.VisitClassBlock(node)
End Function
Public Overrides Function VisitStructureBlock(ByVal node As StructureBlockSyntax) As SyntaxNode
VisitTypeBlockSyntax(node)
Return MyBase.VisitStructureBlock(node)
End Function
Public Overrides Function VisitInterfaceBlock(ByVal node As InterfaceBlockSyntax) As SyntaxNode
VisitTypeBlockSyntax(node)
Return MyBase.VisitInterfaceBlock(node)
End Function
'''
''' We want to display type blocks (Modules, Classes, Structures and Interfaces) like follows
''' Class Foo
''' implements IBar1, IBar2
''' implements IBar3
''' inherits Bar1
'''
''' Public Sub Boo()
''' End Sub
''' End Class
'''
''' or
'''
''' Class Foo
'''
''' Public Sub Boo()
''' End Sub
''' End Class
'''
''' Basically it's an empty line between implements and inherits and between each member. If there are no
''' inherits or implements, add an empty line before the first member.
'''
Private Sub VisitTypeBlockSyntax(ByVal node As TypeBlockSyntax)
Dim hasImplements As Boolean = node.Implements.Count > 0
Dim hasInherits As Boolean = node.Inherits.Count > 0
' add a line break between begin statement and the ones from the statement list
If Not hasInherits AndAlso Not hasImplements AndAlso node.Members.Count > 0 Then
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 2)
Else
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
End If
If hasImplements Then
AddLinebreaksAfterElementsIfNeeded(node.Inherits, 1, 1)
Else
AddLinebreaksAfterElementsIfNeeded(node.Inherits, 1, 2)
End If
AddLinebreaksAfterElementsIfNeeded(node.Implements, 1, 2)
If node.Kind = SyntaxKind.InterfaceBlock Then
AddLinebreaksAfterElementsIfNeeded(node.Members, 2, 2)
Else
AddLinebreaksAfterElementsIfNeeded(node.Members, 2, 1)
End If
End Sub
Public Overrides Function VisitMultiLineIfBlock(node As MultiLineIfBlockSyntax) As SyntaxNode
Dim previousPart = node.IfPart
For Each elseIfPart In (node.ElseIfParts)
AddLinebreaksAfterTokenIfNeeded(previousPart.GetLastToken(), 1)
previousPart = elseIfPart
Next
If node.ElsePart IsNot Nothing Then
AddLinebreaksAfterTokenIfNeeded(previousPart.GetLastToken(), 1)
End If
If Not lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.End.GetLastToken(), 2)
Else
AddLinebreaksAfterTokenIfNeeded(node.End.GetLastToken(), 1)
End If
Return MyBase.VisitMultiLineIfBlock(node)
End Function
Public Overrides Function VisitEventBlock(node As EventBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.EventStatement.GetLastToken, 1)
AddLinebreaksAfterElementsIfNeeded(node.Accessors, 2, 1)
Return MyBase.VisitEventBlock(node)
End Function
Public Overrides Function VisitDoLoopBlock(node As DoLoopBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.DoStatement.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
If lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.LoopStatement.GetLastToken(), 1)
Else
AddLinebreaksAfterTokenIfNeeded(node.LoopStatement.GetLastToken(), 2)
End If
Return MyBase.VisitDoLoopBlock(node)
End Function
Public Overrides Function VisitSyncLockBlock(node As SyncLockBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.SyncLockStatement.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
If lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.EndSyncLockStatement.GetLastToken(), 1)
Else
AddLinebreaksAfterTokenIfNeeded(node.EndSyncLockStatement.GetLastToken(), 2)
End If
Return MyBase.VisitSyncLockBlock(node)
End Function
Public Overrides Function VisitMethodBlock(node As MethodBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Return MyBase.VisitMethodBlock(node)
End Function
Public Overrides Function VisitConstructorBlock(node As ConstructorBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Return MyBase.VisitConstructorBlock(node)
End Function
Public Overrides Function VisitOperatorBlock(node As OperatorBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Return MyBase.VisitOperatorBlock(node)
End Function
Public Overrides Function VisitAccessorBlock(node As AccessorBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Return MyBase.VisitAccessorBlock(node)
End Function
'''
''' Each statement and the begin will be displayed on a separate line. No empty lines.
'''
Public Overrides Function VisitEnumBlock(node As EnumBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.EnumStatement.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Members, 1, 1)
Return MyBase.VisitEnumBlock(node)
End Function
Public Overrides Function VisitWhileBlock(node As WhileBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.WhileStatement.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
If Not lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.EndWhileStatement.GetLastToken(), 2)
End If
Return MyBase.VisitWhileBlock(node)
End Function
Public Overrides Function VisitForBlock(node As ForBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
If node.NextStatement IsNot Nothing Then
If Not lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.NextStatement.GetLastToken(), 2)
Else
AddLinebreaksAfterTokenIfNeeded(node.NextStatement.GetLastToken(), 1)
End If
End If
Return MyBase.VisitForBlock(node)
End Function
Public Overrides Function VisitUsingBlock(node As UsingBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.UsingStatement.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
If Not lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.EndUsingStatement.GetLastToken(), 2)
Else
AddLinebreaksAfterTokenIfNeeded(node.EndUsingStatement.GetLastToken(), 1)
End If
Return MyBase.VisitUsingBlock(node)
End Function
Public Overrides Function VisitWithBlock(node As WithBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.WithStatement.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Return MyBase.VisitWithBlock(node)
End Function
Public Overrides Function VisitSelectBlock(node As SelectBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.SelectStatement.GetLastToken(), 1)
If Not lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.EndSelectStatement.GetLastToken(), 2)
Else
AddLinebreaksAfterTokenIfNeeded(node.EndSelectStatement.GetLastToken(), 1)
End If
Return MyBase.VisitSelectBlock(node)
End Function
Public Overrides Function VisitCaseBlock(node As CaseBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
Dim result = MyBase.VisitCaseBlock(node)
indentationDepth -= 1
Return result
End Function
Public Overrides Function VisitTryBlock(node As TryBlockSyntax) As SyntaxNode
If Not lastStatementsInBlocks.Contains(node) Then
AddLinebreaksAfterTokenIfNeeded(node.End.GetLastToken(), 2)
Else
AddLinebreaksAfterTokenIfNeeded(node.End.GetLastToken(), 1)
End If
Return MyBase.VisitTryBlock(node)
End Function
Public Overrides Function VisitTryPart(node As TryPartSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Dim result = MyBase.VisitTryPart(node)
indentationDepth -= 1
Return result
End Function
Public Overrides Function VisitCatchPart(node As CatchPartSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
Dim result = MyBase.VisitCatchPart(node)
indentationDepth -= 1
Return result
End Function
Public Overrides Function VisitFinallyPart(node As FinallyPartSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Dim result = MyBase.VisitFinallyPart(node)
indentationDepth -= 1
Return result
End Function
Public Overrides Function VisitPropertyBlock(node As PropertyBlockSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.PropertyStatement.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Accessors, 2, 1)
Return MyBase.VisitPropertyBlock(node)
End Function
Public Overrides Function VisitIfPart(node As IfPartSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Dim result = MyBase.VisitIfPart(node)
indentationDepth -= 1
Return result
End Function
Public Overrides Function VisitElsePart(node As ElsePartSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
Dim result = MyBase.VisitElsePart(node)
indentationDepth -= 1
Return result
End Function
Public Overrides Function VisitMultiLineLambdaExpression(node As MultiLineLambdaExpressionSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.Begin.GetLastToken(), 1)
' one statement per line
AddLinebreaksAfterElementsIfNeeded(node.Statements, 1, 1)
MarkLastStatementIfNeeded(node.Statements)
indentationDepth += 1
Dim result = MyBase.VisitMultiLineLambdaExpression(node)
Return result
End Function
Public Overrides Function VisitConstDirectiveTrivia(node As ConstDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitConstDirectiveTrivia(node)
End Function
Public Overrides Function VisitIfDirectiveTrivia(node As IfDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitIfDirectiveTrivia(node)
End Function
Public Overrides Function VisitElseDirectiveTrivia(node As ElseDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitElseDirectiveTrivia(node)
End Function
Public Overrides Function VisitEndIfDirectiveTrivia(node As EndIfDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitEndIfDirectiveTrivia(node)
End Function
Public Overrides Function VisitRegionDirectiveTrivia(node As RegionDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitRegionDirectiveTrivia(node)
End Function
Public Overrides Function VisitEndRegionDirectiveTrivia(node As EndRegionDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitEndRegionDirectiveTrivia(node)
End Function
Public Overrides Function VisitExternalSourceDirectiveTrivia(node As ExternalSourceDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitExternalSourceDirectiveTrivia(node)
End Function
Public Overrides Function VisitEndExternalSourceDirectiveTrivia(node As EndExternalSourceDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitEndExternalSourceDirectiveTrivia(node)
End Function
Public Overrides Function VisitExternalChecksumDirectiveTrivia(node As ExternalChecksumDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitExternalChecksumDirectiveTrivia(node)
End Function
Public Overrides Function VisitReferenceDirectiveTrivia(node As ReferenceDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitReferenceDirectiveTrivia(node)
End Function
Public Overrides Function VisitBadDirectiveTrivia(node As BadDirectiveTriviaSyntax) As SyntaxNode
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
Return MyBase.VisitBadDirectiveTrivia(node)
End Function
Public Overrides Function VisitAttributeList(node As AttributeListSyntax) As SyntaxNode
' do not add linebreaks for attributes of parameters or return types
If node.Parent Is Nothing OrElse
(node.Parent.Kind <> SyntaxKind.Parameter AndAlso node.Parent.Kind <> SyntaxKind.SimpleAsClause) Then
AddLinebreaksAfterTokenIfNeeded(node.GetLastToken(), 1)
End If
Return MyBase.VisitAttributeList(node)
End Function
Public Overrides Function VisitEndBlockStatement(node As EndBlockStatementSyntax) As SyntaxNode
' the parts of try and if blocks are responsible to reduce the indentation, so in that case
' don't do anything here.
If node.Kind <> SyntaxKind.EndTryStatement AndAlso node.Kind <> SyntaxKind.EndIfStatement Then
indentationDepth -= 1
End If
Return MyBase.VisitEndBlockStatement(node)
End Function
Public Overrides Function VisitElseStatement(node As ElseStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitElseStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitIfStatement(node As IfStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitIfStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitWithStatement(node As WithStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitWithStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitSyncLockStatement(node As SyncLockStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitSyncLockStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitModuleStatement(node As ModuleStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitModuleStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitNamespaceStatement(node As NamespaceStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitNamespaceStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitInterfaceStatement(node As InterfaceStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitInterfaceStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitStructureStatement(node As StructureStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitStructureStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitEnumStatement(node As EnumStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitEnumStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitClassStatement(node As ClassStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitClassStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitWhileStatement(node As WhileStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitWhileStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitDoStatement(node As DoStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitDoStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitSelectStatement(node As SelectStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitSelectStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitCaseStatement(node As CaseStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitCaseStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitLoopStatement(node As LoopStatementSyntax) As SyntaxNode
indentationDepth -= 1
Return MyBase.VisitLoopStatement(node)
End Function
Public Overrides Function VisitForStatement(node As ForStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitForStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitForEachStatement(node As ForEachStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitForEachStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitTryStatement(node As TryStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitTryStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitCatchStatement(node As CatchStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitCatchStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitFinallyStatement(node As FinallyStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitFinallyStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitUsingStatement(node As UsingStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitUsingStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitMethodStatement(node As MethodStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitMethodStatement(node)
' only indent if this is a block
If node.Parent IsNot Nothing AndAlso
(node.Parent.Kind = SyntaxKind.SubBlock OrElse node.Parent.Kind = SyntaxKind.FunctionBlock) Then
indentationDepth += 1
End If
Return result
End Function
Public Overrides Function VisitSubNewStatement(node As SubNewStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitSubNewStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitAccessorStatement(node As AccessorStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitAccessorStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitOperatorStatement(node As OperatorStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitOperatorStatement(node)
indentationDepth += 1
Return result
End Function
Public Overrides Function VisitEventStatement(node As EventStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitEventStatement(node)
' only indent if this is a block
If node.Parent IsNot Nothing AndAlso node.Parent.Kind = SyntaxKind.EventBlock Then
indentationDepth += 1
End If
Return result
End Function
Public Overrides Function VisitPropertyStatement(node As PropertyStatementSyntax) As SyntaxNode
Dim result = MyBase.VisitPropertyStatement(node)
' only indent if this is a block
If node.Parent IsNot Nothing AndAlso node.Parent.Kind = SyntaxKind.PropertyBlock Then
indentationDepth += 1
End If
Return result
End Function
Public Overrides Function VisitLabelStatement(node As LabelStatementSyntax) As SyntaxNode
' labels are never indented.
Dim previousIndentationDepth = indentationDepth
indentationDepth = 0
Dim result = MyBase.VisitLabelStatement(node)
indentationDepth = previousIndentationDepth
Return result
End Function
Public Overrides Function VisitNextStatement(node As NextStatementSyntax) As SyntaxNode
' next statements with multiple control variables are attached to the inner most for statement,
' but it should be indented as it is attached to the outer most one.
Dim variableCount = node.ControlVariables.Count
If variableCount = 0 Then
variableCount = 1
End If
indentationDepth -= variableCount
Return MyBase.VisitNextStatement(node)
End Function
End Class
End Namespace