File: Compilation\DocumentationComments\UnprocessedDocumentationCommentFinder.vb
Web Access
Project: src\src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.

Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.Text

Namespace Microsoft.CodeAnalysis.VisualBasic
    Partial Public Class VisualBasicCompilation
        Partial Friend Class DocumentationCommentCompiler
            Inherits VisualBasicSymbolVisitor

            Private Class MislocatedDocumentationCommentFinder
                Inherits VisualBasicSyntaxWalker

                Private ReadOnly _diagnostics As DiagnosticBag
                Private ReadOnly _filterSpanWithinTree As TextSpan?
                Private ReadOnly _cancellationToken As CancellationToken

                Private _isInsideMethodOrLambda As Boolean

                Private Sub New(diagnostics As DiagnosticBag,
                                filterSpanWithinTree As TextSpan?,
                                cancellationToken As CancellationToken)

                    MyBase.New(SyntaxWalkerDepth.Trivia)

                    Debug.Assert(diagnostics IsNot Nothing)
                    Me._diagnostics = diagnostics
                    Me._filterSpanWithinTree = filterSpanWithinTree
                    Me._cancellationToken = cancellationToken

                    Me._isInsideMethodOrLambda = False
                End Sub

                Public Shared Sub ReportUnprocessed(tree As SyntaxTree, filterSpanWithinTree As TextSpan?, diagnostics As DiagnosticBag, cancellationToken As CancellationToken)
                    If tree.ReportDocumentationCommentDiagnostics() Then
                        Dim finder As New MislocatedDocumentationCommentFinder(diagnostics, filterSpanWithinTree, cancellationToken)
                        finder.Visit(tree.GetRoot(cancellationToken))
                    End If
                End Sub

                Private Function IsSyntacticallyFilteredOut(fullSpan As TextSpan) As Boolean
                    Return Me._filterSpanWithinTree.HasValue AndAlso Not Me._filterSpanWithinTree.Value.Contains(fullSpan)
                End Function

                Public Overrides Sub VisitMethodBlock(node As MethodBlockSyntax)
                    VisitMethodBlockBase(node)
                End Sub

                Public Overrides Sub VisitConstructorBlock(node As ConstructorBlockSyntax)
                    VisitMethodBlockBase(node)
                End Sub

                Public Overrides Sub VisitOperatorBlock(node As OperatorBlockSyntax)
                    VisitMethodBlockBase(node)
                End Sub

                Public Overrides Sub VisitAccessorBlock(node As AccessorBlockSyntax)
                    VisitMethodBlockBase(node)
                End Sub

                Private Sub VisitMethodBlockBase(node As Syntax.MethodBlockBaseSyntax)
                    Me._cancellationToken.ThrowIfCancellationRequested()

                    If IsSyntacticallyFilteredOut(node.FullSpan) Then
                        Return
                    End If

                    Dim stored = Me._isInsideMethodOrLambda

                    ' Visit block start statement
                    Me._isInsideMethodOrLambda = False
                    Me.Visit(node.BlockStatement)

                    ' Visit the rest 
                    Me._isInsideMethodOrLambda = True
                    Me.DefaultVisitChildrenStartingWith(node, 1)

                    Me._isInsideMethodOrLambda = stored
                End Sub

                Public Overrides Sub VisitMultiLineLambdaExpression(node As Syntax.MultiLineLambdaExpressionSyntax)
                    Me._cancellationToken.ThrowIfCancellationRequested()

                    If IsSyntacticallyFilteredOut(node.FullSpan) Then
                        Return
                    End If

                    Dim stored = Me._isInsideMethodOrLambda
                    Me._isInsideMethodOrLambda = True  ' Any doc comment inside this block is an error

                    MyBase.VisitMultiLineLambdaExpression(node)

                    Me._isInsideMethodOrLambda = stored
                End Sub

                Public Overrides Sub DefaultVisit(node As SyntaxNode)
                    ' Short-circuit traversal if we know there are no documentation comments below.
                    If node.HasStructuredTrivia AndAlso Not IsSyntacticallyFilteredOut(node.FullSpan) Then
                        MyBase.DefaultVisit(node)
                    End If
                End Sub

                Private Sub DefaultVisitChildrenStartingWith(node As SyntaxNode, start As Integer)
                    Dim list = node.ChildNodesAndTokens()
                    Dim childCnt = list.Count

                    Dim i As Integer = start
                    While i < childCnt
                        Dim child = list(i)
                        i = i + 1

                        Dim asNode = child.AsNode()
                        If asNode IsNot Nothing Then
                            Me.Visit(asNode)
                        Else
                            Me.VisitToken(child.AsToken())
                        End If
                    End While
                End Sub

                Public Overrides Sub VisitTrivia(trivia As SyntaxTrivia)
                    If IsSyntacticallyFilteredOut(trivia.FullSpan) Then
                        Return
                    End If

                    If trivia.Kind = SyntaxKind.DocumentationCommentTrivia Then
                        If Me._isInsideMethodOrLambda Then
                            Me._diagnostics.Add(ERRID.WRN_XMLDocInsideMethod, trivia.GetLocation())

                        Else
                            Dim parent As VisualBasicSyntaxNode = DirectCast(trivia.Token.Parent, VisualBasicSyntaxNode)
lAgain:
                            Debug.Assert(parent IsNot Nothing)
                            Select Case parent.Kind
                                Case SyntaxKind.ClassStatement,
                                     SyntaxKind.EnumStatement,
                                     SyntaxKind.InterfaceStatement,
                                     SyntaxKind.StructureStatement,
                                     SyntaxKind.ModuleStatement,
                                     SyntaxKind.SubStatement,
                                     SyntaxKind.SubNewStatement,
                                     SyntaxKind.FunctionStatement,
                                     SyntaxKind.DelegateSubStatement,
                                     SyntaxKind.DelegateFunctionStatement,
                                     SyntaxKind.DeclareSubStatement,
                                     SyntaxKind.DeclareFunctionStatement,
                                     SyntaxKind.OperatorStatement,
                                     SyntaxKind.PropertyStatement,
                                     SyntaxKind.EventStatement,
                                     SyntaxKind.FieldDeclaration,
                                     SyntaxKind.EnumMemberDeclaration
                                    ' Do nothing, the comment is properly located

                                Case SyntaxKind.AttributeList
                                    parent = parent.Parent
                                    GoTo lAgain

                                Case Else
                                    Me._diagnostics.Add(ERRID.WRN_XMLDocWithoutLanguageElement, trivia.GetLocation())

                            End Select
                        End If
                    End If

                    MyBase.VisitTrivia(trivia)
                End Sub

            End Class

        End Class
    End Class
End Namespace