File: Rename\LocalConflictVisitor.vb
Web Access
Project: src\src\Workspaces\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj (Microsoft.CodeAnalysis.VisualBasic.Workspaces)
' 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.Threading
Imports Microsoft.CodeAnalysis.Rename.ConflictEngine
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Rename
    Friend Class LocalConflictVisitor
        Inherits VisualBasicSyntaxVisitor
 
        Private ReadOnly _tracker As ConflictingIdentifierTracker
        Private ReadOnly _semanticModel As SemanticModel
        Private ReadOnly _cancellationToken As CancellationToken
 
        Public Sub New(tokenBeingRenamed As SyntaxToken, semanticModel As SemanticModel, cancellationToken As CancellationToken)
            _tracker = New ConflictingIdentifierTracker(tokenBeingRenamed, CaseInsensitiveComparison.Comparer)
            _semanticModel = semanticModel
            _cancellationToken = cancellationToken
        End Sub
 
        Public Overrides Sub DefaultVisit(node As SyntaxNode)
            For Each child In node.ChildNodes()
                Visit(child)
            Next
        End Sub
 
        Private Sub VisitMethodBlockBase(node As MethodBlockBaseSyntax)
            Dim tokens As New List(Of SyntaxToken)
 
            If node.BlockStatement.ParameterList IsNot Nothing Then
                tokens.AddRange(From parameter In node.BlockStatement.ParameterList.Parameters
                                Select parameter.Identifier.Identifier)
            End If
 
            _tracker.AddIdentifiers(tokens)
            VisitBlock(node.Statements)
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        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
 
        Public Overrides Sub VisitQueryExpression(node As QueryExpressionSyntax)
            Dim tokens As New List(Of SyntaxToken)
 
            ' TODO: fully implement handling of all range vars incl. hiding rules.
 
            For Each clause In node.Clauses
 
                Select Case clause.Kind
                    Case SyntaxKind.FromClause
                        tokens.AddRange(From variable In DirectCast(clause, FromClauseSyntax).Variables
                                        Select variable.Identifier.Identifier)
                End Select
            Next
 
            _tracker.AddIdentifiers(tokens)
            For Each clause In node.Clauses
                Visit(clause)
            Next
 
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        Private Sub VisitBlock(block As SyntaxList(Of StatementSyntax))
            Dim tokens As New List(Of SyntaxToken)
 
            For Each statement In block
                If statement.Kind = SyntaxKind.LocalDeclarationStatement Then
                    Dim declarationStatement = DirectCast(statement, LocalDeclarationStatementSyntax)
 
                    For Each declarator In declarationStatement.Declarators
                        tokens.AddRange(From i In declarator.Names
                                        Select i.Identifier)
                    Next
                End If
            Next
 
            _tracker.AddIdentifiers(tokens)
            For Each statement In block
                Visit(statement)
            Next
 
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        Public Overrides Sub VisitSingleLineLambdaExpression(node As SingleLineLambdaExpressionSyntax)
            Dim tokens As New List(Of SyntaxToken)
 
            If node.SubOrFunctionHeader.ParameterList IsNot Nothing Then
                tokens.AddRange(From parameter In node.SubOrFunctionHeader.ParameterList.Parameters
                                Select parameter.Identifier.Identifier)
            End If
 
            _tracker.AddIdentifiers(tokens)
            Visit(node.Body)
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        Public Overrides Sub VisitMultiLineLambdaExpression(node As MultiLineLambdaExpressionSyntax)
            Dim tokens As New List(Of SyntaxToken)
 
            If node.SubOrFunctionHeader.ParameterList IsNot Nothing Then
                tokens.AddRange(From parameter In node.SubOrFunctionHeader.ParameterList.Parameters
                                Select parameter.Identifier.Identifier)
            End If
 
            _tracker.AddIdentifiers(tokens)
            VisitBlock(node.Statements)
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        Public Overrides Sub VisitForBlock(node As ForBlockSyntax)
            VisitForOrForEachBlock(node)
        End Sub
 
        Public Overrides Sub VisitForEachBlock(node As ForEachBlockSyntax)
            VisitForOrForEachBlock(node)
        End Sub
 
        Private Sub VisitForOrForEachBlock(node As ForOrForEachBlockSyntax)
            Dim tokens As New List(Of SyntaxToken)
 
            Dim controlVariable As SyntaxNode
            If node.ForOrForEachStatement.Kind = SyntaxKind.ForEachStatement Then
                controlVariable = DirectCast(node.ForOrForEachStatement, ForEachStatementSyntax).ControlVariable
            Else
                controlVariable = DirectCast(node.ForOrForEachStatement, ForStatementSyntax).ControlVariable
            End If
 
            If controlVariable.Kind = SyntaxKind.VariableDeclarator Then
                ' it's only legal to have one name in the variable declarator for for and foreach loops.
                tokens.Add(DirectCast(controlVariable, VariableDeclaratorSyntax).Names.First().Identifier)
            Else
                Dim symbol = _semanticModel.GetSymbolInfo(controlVariable, _cancellationToken).Symbol
 
                ' if it is a field we don't care
                If symbol IsNot Nothing AndAlso symbol.IsKind(SymbolKind.Local) Then
                    Dim local = DirectCast(symbol, ILocalSymbol)
 
                    ' is this local declared in the for or for each loop?
                    ' if not it was already added to the tracker before.
                    If local.IsFor OrElse local.IsForEach Then
                        If controlVariable.Kind = SyntaxKind.IdentifierName Then
                            tokens.Add(DirectCast(controlVariable, IdentifierNameSyntax).Identifier)
                        Else
                            Debug.Fail($"Unexpected control variable kind '{controlVariable.Kind}'")
                        End If
                    End If
                End If
            End If
 
            _tracker.AddIdentifiers(tokens)
            VisitBlock(node.Statements)
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        Public Overrides Sub VisitUsingBlock(node As UsingBlockSyntax)
            Dim tokens As New List(Of SyntaxToken)
 
            ' add all declared variable names to token list
            For Each usingVariableDeclarator In node.UsingStatement.Variables
                For Each name In usingVariableDeclarator.Names
                    tokens.Add(name.Identifier)
                Next
            Next
 
            _tracker.AddIdentifiers(tokens)
            VisitBlock(node.Statements)
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        Public Overrides Sub VisitCatchBlock(node As CatchBlockSyntax)
            Dim tokens As New List(Of SyntaxToken)
 
            Dim identifierToken = node.CatchStatement.IdentifierName?.Identifier
 
            If identifierToken.HasValue Then
                Dim symbol = _semanticModel.GetSymbolInfo(identifierToken.Value, _cancellationToken).Symbol
 
                ' if it is a field we don't care
                If symbol IsNot Nothing AndAlso symbol.IsKind(SymbolKind.Local) Then
                    Dim local = DirectCast(symbol, ILocalSymbol)
 
                    ' is this local declared in the for or for each loop?
                    ' if not it was already added to the tracker before.
                    If local.IsCatch Then
                        tokens.Add(identifierToken.Value)
                    End If
                End If
            End If
 
            _tracker.AddIdentifiers(tokens)
            VisitBlock(node.Statements)
            _tracker.RemoveIdentifiers(tokens)
        End Sub
 
        Public ReadOnly Property ConflictingTokens As IEnumerable(Of SyntaxToken)
            Get
                Return _tracker.ConflictingTokens
            End Get
        End Property
    End Class
End Namespace