File: Diagnostics\Analyzers\VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb
Web Access
Project: src\src\Features\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Features.vbproj (Microsoft.CodeAnalysis.VisualBasic.Features)
' 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.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeStyle
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Shared.Collections
Imports Microsoft.CodeAnalysis.SimplifyTypeNames
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Simplification
Imports Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames
 
    <DiagnosticAnalyzer(LanguageNames.VisualBasic)>
    Friend NotInheritable Class VisualBasicSimplifyTypeNamesDiagnosticAnalyzer
        Inherits SimplifyTypeNamesDiagnosticAnalyzerBase(Of SyntaxKind, VisualBasicSimplifierOptions)
 
        Private Shared ReadOnly s_kindsOfInterest As ImmutableArray(Of SyntaxKind) = ImmutableArray.Create(
            SyntaxKind.QualifiedName,
            SyntaxKind.SimpleMemberAccessExpression,
            SyntaxKind.IdentifierName,
            SyntaxKind.GenericName)
 
        Protected Overrides Function IsIgnoredCodeBlock(codeBlock As SyntaxNode) As Boolean
            ' Avoid analysis of compilation units and types in AnalyzeCodeBlock. These nodes appear in code block
            ' callbacks when they include attributes, but analysis of the node at this level would block more efficient
            ' analysis of descendant members.
            Return codeBlock.IsKind(SyntaxKind.CompilationUnit, SyntaxKind.ClassBlock, SyntaxKind.StructureBlock) OrElse
                codeBlock.IsKind(SyntaxKind.InterfaceBlock, SyntaxKind.ModuleBlock, SyntaxKind.EnumBlock) OrElse
                codeBlock.IsKind(SyntaxKind.DelegateFunctionStatement)
        End Function
 
        Protected Overrides Function AnalyzeCodeBlock(context As CodeBlockAnalysisContext, root As SyntaxNode) As ImmutableArray(Of Diagnostic)
            Debug.Assert(context.CodeBlock.DescendantNodesAndSelf().Contains(root))
 
            Dim semanticModel = context.SemanticModel
            Dim cancellationToken = context.CancellationToken
 
            Dim simplifierOptions = context.GetVisualBasicAnalyzerOptions().GetSimplifierOptions()
            If (ShouldSkipAnalysis(context.FilterTree, context.Options, context.SemanticModel.Compilation.Options, GetAllNotifications(simplifierOptions), cancellationToken)) Then
                Return ImmutableArray(Of Diagnostic).Empty
            End If
 
            Dim simplifier As New TypeSyntaxSimplifierWalker(Me, semanticModel, simplifierOptions, context.Options, ignoredSpans:=Nothing, cancellationToken)
            simplifier.Visit(root)
            Return simplifier.Diagnostics
        End Function
 
        Protected Overrides Function AnalyzeSemanticModel(context As SemanticModelAnalysisContext, root As SyntaxNode, codeBlockIntervalTree As TextSpanMutableIntervalTree) As ImmutableArray(Of Diagnostic)
            Dim simplifierOptions = context.GetVisualBasicAnalyzerOptions().GetSimplifierOptions()
            If (ShouldSkipAnalysis(context.FilterTree, context.Options, context.SemanticModel.Compilation.Options, GetAllNotifications(simplifierOptions), context.CancellationToken)) Then
                Return ImmutableArray(Of Diagnostic).Empty
            End If
 
            Dim configOptions = context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.SemanticModel.SyntaxTree)
            Dim simplifier As New TypeSyntaxSimplifierWalker(Me, context.SemanticModel, simplifierOptions, context.Options, ignoredSpans:=codeBlockIntervalTree, context.CancellationToken)
            simplifier.Visit(root)
            Return simplifier.Diagnostics
        End Function
 
        Private Shared Function IsNodeKindInteresting(node As SyntaxNode) As Boolean
            Return s_kindsOfInterest.Contains(node.Kind)
        End Function
 
        Friend Overrides Function IsCandidate(node As SyntaxNode) As Boolean
            Return node IsNot Nothing AndAlso IsNodeKindInteresting(node)
        End Function
 
        Friend Overrides Function CanSimplifyTypeNameExpression(
                model As SemanticModel, node As SyntaxNode, options As VisualBasicSimplifierOptions,
                ByRef issueSpan As TextSpan, ByRef diagnosticId As String, ByRef inDeclaration As Boolean,
                cancellationToken As CancellationToken) As Boolean
            issueSpan = Nothing
            diagnosticId = IDEDiagnosticIds.SimplifyNamesDiagnosticId
 
            Dim memberAccess = TryCast(node, MemberAccessExpressionSyntax)
            If memberAccess IsNot Nothing AndAlso memberAccess.Expression.IsKind(SyntaxKind.MeExpression) Then
                ' don't bother analyzing "me.Goo" expressions.  They will be analyzed by
                ' the VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.
                Return False
            End If
 
            Dim expression = DirectCast(node, ExpressionSyntax)
            If expression.ContainsDiagnostics Then
                Return False
            End If
 
            Dim replacementSyntax As ExpressionSyntax = Nothing
            If Not ExpressionSimplifier.Instance.TrySimplify(expression, model, options, replacementSyntax, issueSpan, cancellationToken) Then
                Return False
            End If
 
            ' set proper diagnostic ids.
            If replacementSyntax.HasAnnotations(NameOf(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration)) Then
                inDeclaration = True
                diagnosticId = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId
            ElseIf replacementSyntax.HasAnnotations(NameOf(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess)) Then
                inDeclaration = False
                diagnosticId = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId
            ElseIf expression.Kind = SyntaxKind.SimpleMemberAccessExpression Then
                Dim method = model.GetMemberGroup(expression, cancellationToken)
                If method.Length = 1 Then
                    Dim symbol = method.First()
                    If (symbol.IsOverrides Or symbol.IsOverridable) And memberAccess.Expression.Kind = SyntaxKind.MyClassExpression Then
                        Return False
                    End If
                End If
 
                diagnosticId = IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId
            End If
 
            Return True
        End Function
    End Class
End Namespace