File: Compilation\DocumentationComments\UnprocessedDocumentationCommentFinder.vb
Web Access
Project: src\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