PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Features/VisualBasic/Portable/CodeFixes/RemoveUnnecessaryCast/RemoveUnnecessaryCastCodeFixProvider.vb

https://gitlab.com/sharadag/Roslyn
Visual Basic | 194 lines | 146 code | 40 blank | 8 comment | 0 complexity | 8ec114fc6c0ed987c37b4c99357ad61c MD5 | raw file
  1. ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. Imports System.Collections.Immutable
  3. Imports System.Composition
  4. Imports System.Threading
  5. Imports Microsoft.CodeAnalysis.CodeActions
  6. Imports Microsoft.CodeAnalysis.CodeFixes
  7. Imports Microsoft.CodeAnalysis.Diagnostics
  8. Imports Microsoft.CodeAnalysis.Formatting
  9. Imports Microsoft.CodeAnalysis.Simplification
  10. Imports Microsoft.CodeAnalysis.Text
  11. Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
  12. Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.RemoveUnnecessaryCast
  13. <ExportCodeFixProviderAttribute(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.RemoveUnnecessaryCast), [Shared]>
  14. <ExtensionOrder(After:=PredefinedCodeFixProviderNames.GenerateEndConstruct)>
  15. Partial Friend Class RemoveUnnecessaryCastCodeFixProvider
  16. Inherits CodeFixProvider
  17. Public NotOverridable Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String)
  18. Get
  19. Return ImmutableArray.Create(IDEDiagnosticIds.RemoveUnnecessaryCastDiagnosticId)
  20. End Get
  21. End Property
  22. Public NotOverridable Overrides Async Function RegisterCodeFixesAsync(context As CodeFixContext) As Task
  23. Dim document = context.Document
  24. Dim span = context.Span
  25. Dim cancellationToken = context.CancellationToken
  26. Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False)
  27. Dim model = DirectCast(Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False), SemanticModel)
  28. Dim node = GetCastNode(root, model, span, cancellationToken)
  29. If node Is Nothing Then
  30. Return
  31. End If
  32. context.RegisterCodeFix(
  33. New MyCodeAction(
  34. VBFeaturesResources.RemoveUnnecessaryCast,
  35. Function(c) RemoveUnnecessaryCastAsync(document, node, c)),
  36. context.Diagnostics)
  37. End Function
  38. Private Shared Function GetCastNode(root As SyntaxNode, model As SemanticModel, span As TextSpan, cancellationToken As CancellationToken) As ExpressionSyntax
  39. Dim token = root.FindToken(span.Start)
  40. If Not token.Span.IntersectsWith(span) Then
  41. Return Nothing
  42. End If
  43. Dim node = token.GetAncestors(Of ExpressionSyntax)() _
  44. .Where(Function(c) TypeOf c Is CastExpressionSyntax OrElse TypeOf c Is PredefinedCastExpressionSyntax) _
  45. .FirstOrDefault(Function(c) c.Span.IntersectsWith(span) AndAlso IsUnnecessaryCast(c, model, cancellationToken))
  46. Return node
  47. End Function
  48. Private Shared Function IsUnnecessaryCast(node As ExpressionSyntax, model As SemanticModel, cancellationToken As CancellationToken) As Boolean
  49. Dim castExpression = TryCast(node, CastExpressionSyntax)
  50. If castExpression IsNot Nothing Then
  51. Return castExpression.IsUnnecessaryCast(model, assumeCallKeyword:=True, cancellationToken:=cancellationToken)
  52. End If
  53. Dim predefinedCastExpression = TryCast(node, PredefinedCastExpressionSyntax)
  54. If predefinedCastExpression IsNot Nothing Then
  55. Return predefinedCastExpression.IsUnnecessaryCast(model, assumeCallKeyword:=True, cancellationToken:=cancellationToken)
  56. End If
  57. Return False
  58. End Function
  59. Private Shared Async Function RemoveUnnecessaryCastAsync(document As Document, node As ExpressionSyntax, cancellationToken As CancellationToken) As Task(Of Document)
  60. ' First, annotate our expression so that we can get back to it.
  61. Dim updatedDocument = Await document.ReplaceNodeAsync(node, node.WithAdditionalAnnotations(s_expressionAnnotation), cancellationToken).ConfigureAwait(False)
  62. Dim expression = Await FindNodeWithAnnotationAsync(Of ExpressionSyntax)(s_expressionAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False)
  63. ' Next, make the parenting statement of the expression semantically explicit
  64. Dim parentStatement = expression.FirstAncestorOrSelf(Of StatementSyntax)()
  65. Dim explicitParentStatement = Await Simplifier.ExpandAsync(parentStatement, updatedDocument, cancellationToken:=cancellationToken).ConfigureAwait(False)
  66. explicitParentStatement = explicitParentStatement.WithAdditionalAnnotations(Formatter.Annotation, s_statementAnnotation)
  67. updatedDocument = Await updatedDocument.ReplaceNodeAsync(parentStatement, explicitParentStatement, cancellationToken).ConfigureAwait(False)
  68. ' Next, make the statement after the parenting statement of the expression semantically explicit.
  69. parentStatement = Await FindNodeWithAnnotationAsync(Of StatementSyntax)(s_statementAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False)
  70. Dim nextStatement = parentStatement.GetNextStatement()
  71. If nextStatement IsNot Nothing Then
  72. Dim explicitNextStatement = Await Simplifier.ExpandAsync(nextStatement, updatedDocument, cancellationToken:=cancellationToken).ConfigureAwait(False)
  73. updatedDocument = Await updatedDocument.ReplaceNodeAsync(nextStatement, explicitNextStatement, cancellationToken).ConfigureAwait(False)
  74. End If
  75. updatedDocument = Await RewriteCoreAsync(updatedDocument, expression, cancellationToken).ConfigureAwait(False)
  76. ' Remove added _expressionAnnotation and _statementAnnotation.
  77. updatedDocument = Await RemoveNodesAndTokensWithAnnotationAsync(s_expressionAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False)
  78. updatedDocument = Await RemoveNodesAndTokensWithAnnotationAsync(s_statementAnnotation, updatedDocument, cancellationToken).ConfigureAwait(False)
  79. Return updatedDocument
  80. End Function
  81. Private Shared Async Function RemoveNodesAndTokensWithAnnotationAsync(annotation As SyntaxAnnotation, document As Document, cancellationToken As CancellationToken) As Task(Of Document)
  82. Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False)
  83. Dim nodesWithAnnotation = Await FindNodesWithAnnotationAsync(annotation, document, cancellationToken).ConfigureAwait(False)
  84. root = root.ReplaceSyntax(
  85. nodesWithAnnotation.Where(Function(n) n.IsNode).Select(Function(n) n.AsNode),
  86. Function(o, n) o.WithoutAnnotations(annotation),
  87. nodesWithAnnotation.Where(Function(n) n.IsToken).Select(Function(n) n.AsToken),
  88. Function(o, n) o.WithoutAnnotations(annotation),
  89. SpecializedCollections.EmptyEnumerable(Of SyntaxTrivia),
  90. Nothing)
  91. Return document.WithSyntaxRoot(root)
  92. End Function
  93. Private Shared Async Function RewriteCoreAsync(document As Document, originalExpr As ExpressionSyntax, cancellationToken As CancellationToken) As Task(Of Document)
  94. ' Finally, rewrite the cast expression
  95. Dim exprToRewrite As ExpressionSyntax = Nothing
  96. Dim annotatedNodes = Await FindNodesWithAnnotationAsync(s_expressionAnnotation, document, cancellationToken).ConfigureAwait(False)
  97. For Each annotatedNode In annotatedNodes
  98. exprToRewrite = TryCast(annotatedNode.AsNode, ExpressionSyntax)
  99. If exprToRewrite IsNot Nothing AndAlso exprToRewrite.IsKind(originalExpr.Kind) Then
  100. If annotatedNodes.Count > 1 Then
  101. ' Ensure cast is unnecessary
  102. Dim model = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False)
  103. If IsUnnecessaryCast(exprToRewrite, model, cancellationToken) Then
  104. Exit For
  105. End If
  106. Else
  107. Exit For
  108. End If
  109. End If
  110. exprToRewrite = Nothing
  111. Next
  112. If exprToRewrite Is Nothing Then
  113. Return document
  114. End If
  115. Dim rewriter = New Rewriter(exprToRewrite)
  116. Dim newExpression = rewriter.Visit(exprToRewrite)
  117. ' Remove the annotation from the expression so that it isn't hanging around later.
  118. If newExpression.HasAnnotation(s_expressionAnnotation) Then
  119. newExpression = newExpression.WithoutAnnotations(s_expressionAnnotation)
  120. ElseIf newExpression.IsKind(SyntaxKind.ParenthesizedExpression) Then
  121. Dim parenthesizedExpression = DirectCast(newExpression, ParenthesizedExpressionSyntax)
  122. If parenthesizedExpression.Expression.HasAnnotation(s_expressionAnnotation) Then
  123. newExpression = parenthesizedExpression _
  124. .WithExpression(parenthesizedExpression.Expression.WithoutAnnotations(s_expressionAnnotation))
  125. End If
  126. End If
  127. document = Await document.ReplaceNodeAsync(exprToRewrite, newExpression, cancellationToken).ConfigureAwait(False)
  128. If annotatedNodes.Count > 1 Then
  129. Return Await RewriteCoreAsync(document, originalExpr, cancellationToken).ConfigureAwait(False)
  130. End If
  131. Return document
  132. End Function
  133. Private Shared ReadOnly s_expressionAnnotation As New SyntaxAnnotation
  134. Private Shared ReadOnly s_statementAnnotation As New SyntaxAnnotation
  135. Private Shared Async Function FindNodeWithAnnotationAsync(Of T As SyntaxNode)(annotation As SyntaxAnnotation, document As Document, cancellationToken As CancellationToken) As Task(Of T)
  136. Dim annotatedNodes = Await FindNodesWithAnnotationAsync(annotation, document, cancellationToken).ConfigureAwait(False)
  137. Dim result = annotatedNodes.Single().AsNode()
  138. Return DirectCast(result, T)
  139. End Function
  140. Private Shared Async Function FindNodesWithAnnotationAsync(annotation As SyntaxAnnotation, document As Document, cancellationToken As CancellationToken) As Task(Of IEnumerable(Of SyntaxNodeOrToken))
  141. Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False)
  142. Return root.GetAnnotatedNodesAndTokens(annotation)
  143. End Function
  144. Public NotOverridable Overrides Function GetFixAllProvider() As FixAllProvider
  145. Return RemoveUnnecessaryCastFixAllProvider.Instance
  146. End Function
  147. Private Class MyCodeAction
  148. Inherits CodeAction.DocumentChangeAction
  149. Public Sub New(title As String, createChangedDocument As Func(Of CancellationToken, Task(Of Document)))
  150. MyBase.New(title, createChangedDocument)
  151. End Sub
  152. End Class
  153. End Class
  154. End Namespace