| File: Simplification\Simplifiers\AbstractVisualBasicSimplifier.vb | Web Access |
| Project: src\roslyn\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.Runtime.InteropServices Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.Simplification.Simplifiers Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Friend MustInherit Class AbstractVisualBasicSimplifier(Of TSyntax As SyntaxNode, TSimplifiedSyntax As SyntaxNode) Inherits AbstractSimplifier(Of TSyntax, TSimplifiedSyntax, VisualBasicSimplifierOptions) ''' <summary> ''' Returns the predefined keyword kind for a given special type. ''' </summary> ''' <param name="type">The specialtype of this type.</param> ''' <returns>The keyword kind for a given special type, or SyntaxKind.None if the type name is not a predefined type.</returns> Protected Shared Function GetPredefinedKeywordKind(type As SpecialType) As SyntaxKind Select Case type Case SpecialType.System_Boolean Return SyntaxKind.BooleanKeyword Case SpecialType.System_Byte Return SyntaxKind.ByteKeyword Case SpecialType.System_SByte Return SyntaxKind.SByteKeyword Case SpecialType.System_Int32 Return SyntaxKind.IntegerKeyword Case SpecialType.System_UInt32 Return SyntaxKind.UIntegerKeyword Case SpecialType.System_Int16 Return SyntaxKind.ShortKeyword Case SpecialType.System_UInt16 Return SyntaxKind.UShortKeyword Case SpecialType.System_Int64 Return SyntaxKind.LongKeyword Case SpecialType.System_UInt64 Return SyntaxKind.ULongKeyword Case SpecialType.System_Single Return SyntaxKind.SingleKeyword Case SpecialType.System_Double Return SyntaxKind.DoubleKeyword Case SpecialType.System_Decimal Return SyntaxKind.DecimalKeyword Case SpecialType.System_String Return SyntaxKind.StringKeyword Case SpecialType.System_Char Return SyntaxKind.CharKeyword Case SpecialType.System_Object Return SyntaxKind.ObjectKeyword Case SpecialType.System_DateTime Return SyntaxKind.DateKeyword Case Else Return SyntaxKind.None End Select End Function Protected Shared Function TryReplaceWithAlias( node As ExpressionSyntax, semanticModel As SemanticModel, <Out> ByRef aliasReplacement As IAliasSymbol) As Boolean aliasReplacement = Nothing If Not IsAliasReplaceableExpression(node) Then Return False End If Dim symbol = semanticModel.GetSymbolInfo(node).Symbol If (symbol.IsConstructor()) Then symbol = symbol.ContainingType End If ' The following condition checks if the user has used alias in the original code and ' if so the expression is replaced with the Alias If TypeOf node Is QualifiedNameSyntax Then Dim qualifiedNameNode = DirectCast(node, QualifiedNameSyntax) If qualifiedNameNode.Right.Identifier.HasAnnotations(AliasAnnotation.Kind) Then Dim aliasAnnotationInfo = qualifiedNameNode.Right.Identifier.GetAnnotations(AliasAnnotation.Kind).Single() Dim aliasName = AliasAnnotation.GetAliasName(aliasAnnotationInfo) Dim aliasIdentifier = SyntaxFactory.IdentifierName(aliasName) Dim aliasTypeInfo = semanticModel.GetSpeculativeAliasInfo(node.SpanStart, aliasIdentifier, SpeculativeBindingOption.BindAsTypeOrNamespace) If aliasTypeInfo IsNot Nothing Then aliasReplacement = aliasTypeInfo Return ValidateAliasForTarget(aliasReplacement, semanticModel, node, symbol) End If End If End If If node.Kind = SyntaxKind.IdentifierName AndAlso semanticModel.GetAliasInfo(DirectCast(node, IdentifierNameSyntax)) IsNot Nothing Then Return False End If ' an alias can only replace a type Or namespace If symbol Is Nothing OrElse (symbol.Kind <> SymbolKind.Namespace AndAlso symbol.Kind <> SymbolKind.NamedType) Then Return False End If If symbol Is Nothing OrElse TypeOf (symbol) IsNot INamespaceOrTypeSymbol Then Return False End If Dim preferAliasToQualifiedName = True If TypeOf node Is QualifiedNameSyntax Then Dim qualifiedName = DirectCast(node, QualifiedNameSyntax) If Not qualifiedName.Right.HasAnnotation(Simplifier.SpecialTypeAnnotation) Then Dim type = semanticModel.GetTypeInfo(node).Type If type IsNot Nothing Then Dim keywordKind = GetPredefinedKeywordKind(type.SpecialType) If keywordKind <> SyntaxKind.None Then preferAliasToQualifiedName = False End If End If End If End If aliasReplacement = DirectCast(symbol, INamespaceOrTypeSymbol).GetAliasForSymbol(node, semanticModel) If aliasReplacement IsNot Nothing And preferAliasToQualifiedName Then Return ValidateAliasForTarget(aliasReplacement, semanticModel, node, symbol) End If Return False End Function Private Shared Function IsAliasReplaceableExpression(expression As ExpressionSyntax) As Boolean If expression.Kind = SyntaxKind.IdentifierName OrElse expression.Kind = SyntaxKind.QualifiedName Then Return True End If If expression.Kind = SyntaxKind.SimpleMemberAccessExpression Then Dim memberAccess = DirectCast(expression, MemberAccessExpressionSyntax) Return memberAccess.Expression IsNot Nothing AndAlso IsAliasReplaceableExpression(memberAccess.Expression) End If Return False End Function ' We must verify that the alias actually binds back to the thing it's aliasing. ' It's possible there is another symbol with the same name as the alias that binds first Private Shared Function ValidateAliasForTarget(aliasReplacement As IAliasSymbol, semanticModel As SemanticModel, node As ExpressionSyntax, symbol As ISymbol) As Boolean Dim aliasName = aliasReplacement.Name ' If we're the argument of a NameOf(X.Y) call, then we can't simplify to an ' alias unless the alias has the same name as us (i.e. 'Y'). If node.IsNameOfArgumentExpression() Then Dim nameofValueOpt = semanticModel.GetConstantValue(node.Parent.Parent.Parent) If Not nameofValueOpt.HasValue Then Return False End If Dim existingValue = TryCast(nameofValueOpt.Value, String) If existingValue Is Nothing OrElse existingValue <> aliasName Then Return False End If End If Dim boundSymbols = semanticModel.LookupNamespacesAndTypes(node.SpanStart, name:=aliasName) If boundSymbols.Length = 1 Then Dim boundAlias = TryCast(boundSymbols(0), IAliasSymbol) If boundAlias IsNot Nothing And aliasReplacement.Target.Equals(symbol) Then If symbol.IsAttribute Then boundSymbols = semanticModel.LookupNamespacesAndTypes(node.Span.Start, name:=aliasName + "Attribute") Return boundSymbols.IsEmpty End If Return True End If End If Return False End Function Protected Shared Function PreferPredefinedTypeKeywordInMemberAccess(expression As ExpressionSyntax, options As VisualBasicSimplifierOptions) As Boolean Return (IsDirectChildOfMemberAccessExpression(expression) OrElse IsInCrefReferenceForPredefinedTypeInMemberAccessContext(expression)) AndAlso (Not InsideNameOfExpression(expression)) AndAlso options.PreferPredefinedTypeKeywordInMemberAccess.Value End Function Protected Shared Function InsideNameOfExpression(expr As ExpressionSyntax) As Boolean Dim nameOfExpression = expr.FirstAncestorOrSelf(Of NameOfExpressionSyntax)() Return nameOfExpression IsNot Nothing End Function ''' <Remarks> ''' Note: This helper exists solely to work around Bug 1012713. Once it is fixed, this helper must be ''' deleted in favor of <see cref="InsideCrefReference(ExpressionSyntax)"/>. ''' Context: Bug 1012713 makes it so that the compiler doesn't support <c>PredefinedType.Member</c> inside crefs ''' (i.e. System.Int32.MaxValue is supported but Integer.MaxValue isn't). Until this bug is fixed, we don't ''' support simplifying types names Like System.Int32.MaxValue to Integer.MaxValue. ''' </Remarks> Private Shared Function IsInCrefReferenceForPredefinedTypeInMemberAccessContext(expression As ExpressionSyntax) As Boolean Return (InsideCrefReference(expression) AndAlso Not expression.IsLeftSideOfQualifiedName) End Function End Class End Namespace