File: Binding\EarlyWellKnownAttributeBinder.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.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.RuntimeMembers
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    ''' <summary>
    ''' This is a binder for use when early decoding of well known attributes. The binder will only bind expressions that can appear in an attribute.
    ''' Its purpose is to allow a symbol to safely decode any attribute without the possibility of any attribute related infinite recursion during binding.
    ''' If an attribute and its arguments are valid then this binder returns a BoundAttributeExpression otherwise it returns a BadExpression.
    ''' </summary>
    Friend NotInheritable Class EarlyWellKnownAttributeBinder
        Inherits Binder
 
        Private ReadOnly _owner As Symbol
        Friend Sub New(owner As Symbol, containingBinder As Binder)
            MyBase.New(containingBinder, isEarlyAttributeBinder:=True)
            Me._owner = owner
        End Sub
 
        Public Overrides ReadOnly Property ContainingMember As Symbol
            Get
                Return If(_owner, MyBase.ContainingMember)
            End Get
        End Property
 
        Public Overrides ReadOnly Property AdditionalContainingMembers As ImmutableArray(Of Symbol)
            Get
                Return ImmutableArray(Of Symbol).Empty
            End Get
        End Property
 
        ' This binder is only used to bind expressions in an attribute context.
        Public Overrides ReadOnly Property BindingLocation As BindingLocation
            Get
                Return BindingLocation.Attribute
            End Get
        End Property
 
        ' Hide the GetAttribute overload which takes a diagnostic bag.
        ' This ensures that diagnostics from the early bound attributes are never preserved.
        Friend Shadows Function GetAttribute(node As AttributeSyntax, boundAttributeType As NamedTypeSymbol, <Out> ByRef generatedDiagnostics As Boolean) As SourceAttributeData
            Dim diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=False)
            Dim earlyAttribute = MyBase.GetAttribute(node, boundAttributeType, diagnostics)
            generatedDiagnostics = Not diagnostics.DiagnosticBag.IsEmptyWithoutResolution()
            diagnostics.Free()
            Return earlyAttribute
        End Function
 
        ''' <summary>
        ''' Check that the syntax can appear in an attribute argument.
        ''' </summary>
        Friend Shared Function CanBeValidAttributeArgument(node As ExpressionSyntax, memberAccessBinder As Binder) As Boolean
            Debug.Assert(node IsNot Nothing)
 
            ' 11.2 Constant Expressions
            '
            'A constant expression is an expression whose value can be fully evaluated at compile time. The type of a constant expression can be Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, Char, Single, Double, Decimal, Date, Boolean, String, Object, or any enumeration type. The following constructs are permitted in constant expressions:
            '
            '         Literals (including Nothing).
            '         References to constant type members or constant locals.
            '         References to members of enumeration types.
            '         Parenthesized subexpressions.
            '         Coercion expressions, provided the target type is one of the types listed above. Coercions to and from String are an exception to this rule and are only allowed on null values because String conversions are always done in the current culture of the execution environment at run time. Note that constant coercion expressions can only ever use intrinsic conversions.
            '         The +, – and Not unary operators, provided the operand and result is of a type listed above.
            '         The +, –, *, ^, Mod, /, \, <<, >>, &, And, Or, Xor, AndAlso, OrElse, =, <, >, <>, <=, and => binary operators, provided each operand and result is of a type listed above.
            '         The conditional operator If, provided each operand and result is of a type listed above.
            '         The following run-time functions:
            '            Microsoft.VisualBasic.Strings.ChrW
            '            Microsoft.VisualBasic.Strings.Chr, if the constant value is between 0 and 128
            '            Microsoft.VisualBasic.Strings.AscW, if the constant string is not empty
            '            Microsoft.VisualBasic.Strings.Asc, if the constant string is not empty
            '
            ' In addition, attributes allow array expressions including both array literal and array creation expressions as well as GetType expressions.
 
            Select Case node.Kind
 
                Case _
                    SyntaxKind.NumericLiteralExpression,
                    SyntaxKind.StringLiteralExpression,
                    SyntaxKind.CharacterLiteralExpression,
                    SyntaxKind.TrueLiteralExpression,
                    SyntaxKind.FalseLiteralExpression,
                    SyntaxKind.NothingLiteralExpression,
                    SyntaxKind.DateLiteralExpression
                    ' Literals (including Nothing).
                    Return True
 
                Case _
                    SyntaxKind.SimpleMemberAccessExpression,
                    SyntaxKind.GlobalName,
                    SyntaxKind.IdentifierName,
                    SyntaxKind.PredefinedType
                    ' References to constant type members or constant locals.
                    ' References to members of enumeration types.
                    Return True
 
                Case SyntaxKind.ParenthesizedExpression
                    ' Parenthesized subexpressions.
                    Return True
 
                Case _
                    SyntaxKind.CTypeExpression,
                    SyntaxKind.TryCastExpression,
                    SyntaxKind.DirectCastExpression,
                    SyntaxKind.PredefinedCastExpression
                    ' Coercion expressions, provided the target type is one of the types listed above. 
                    ' Coercions to and from String are an exception to this rule and are only allowed on null values
                    ' because String conversions are always done in the current culture of the execution environment
                    ' at run time. Note that constant coercion expressions can only ever use intrinsic conversions.
                    Return True
 
                Case _
                    SyntaxKind.UnaryPlusExpression,
                    SyntaxKind.UnaryMinusExpression,
                    SyntaxKind.NotExpression
                    ' The +, – and Not unary operators, provided the operand and result is of a type listed above.
                    Return True
 
                Case _
                    SyntaxKind.AddExpression,
                    SyntaxKind.SubtractExpression,
                    SyntaxKind.MultiplyExpression,
                    SyntaxKind.ExponentiateExpression,
                    SyntaxKind.DivideExpression,
                    SyntaxKind.ModuloExpression,
                    SyntaxKind.IntegerDivideExpression,
                    SyntaxKind.LeftShiftExpression,
                    SyntaxKind.RightShiftExpression,
                    SyntaxKind.ConcatenateExpression,
                    SyntaxKind.AndExpression,
                    SyntaxKind.OrExpression,
                    SyntaxKind.ExclusiveOrExpression,
                    SyntaxKind.AndAlsoExpression,
                    SyntaxKind.OrElseExpression,
                    SyntaxKind.EqualsExpression,
                    SyntaxKind.NotEqualsExpression,
                    SyntaxKind.LessThanOrEqualExpression,
                    SyntaxKind.GreaterThanOrEqualExpression,
                    SyntaxKind.LessThanExpression,
                    SyntaxKind.GreaterThanExpression
                    ' The +, –, *, ^, Mod, /, \, <<, >>, &, And, Or, Xor, AndAlso, OrElse, =, <, >, <>, <=, and => binary operators,
                    ' provided each operand and result is of a type listed above.
                    Return True
 
                Case _
                    SyntaxKind.BinaryConditionalExpression,
                    SyntaxKind.TernaryConditionalExpression
                    ' The conditional operator If, provided each operand and result is of a type listed above.
                    Return True
 
                Case SyntaxKind.InvocationExpression
                    ' The following run-time functions may appear in constant expressions:
                    '     Microsoft.VisualBasic.Strings.ChrW
                    '     Microsoft.VisualBasic.Strings.Chr, if the constant value is between 0 and 128
                    '     Microsoft.VisualBasic.Strings.AscW, if the constant string is not empty
                    '     Microsoft.VisualBasic.Strings.Asc, if the constant string is not empty
 
                    Dim invokedExpression = DirectCast(node, InvocationExpressionSyntax).Expression
                    If TypeOf invokedExpression Is MemberAccessExpressionSyntax OrElse TypeOf invokedExpression Is IdentifierNameSyntax Then
                        Dim boundExpression = memberAccessBinder.BindExpression(invokedExpression, BindingDiagnosticBag.Discarded)
 
                        If boundExpression.HasErrors Then
                            Return False
                        End If
 
                        Dim boundMethodGroup = TryCast(boundExpression, BoundMethodGroup)
                        If boundMethodGroup IsNot Nothing AndAlso boundMethodGroup.Methods.Length <> 0 Then
 
                            Dim compilation As VisualBasicCompilation = memberAccessBinder.Compilation
 
                            For Each method In boundMethodGroup.Methods
                                If Not IsConstantOptimizableLibraryMethod(compilation, method) Then
                                    Return False
                                End If
                            Next
 
                            Return True
                        End If
                    End If
 
                    Return False
 
                Case SyntaxKind.CollectionInitializer,
                     SyntaxKind.ArrayCreationExpression,
                     SyntaxKind.GetTypeExpression
                    ' These are not constants and are special for attribute expressions.
                    ' SyntaxKind.CollectionInitializer in this case really means ArrayLiteral, i.e.{1, 2, 3}.
                    ' SyntaxKind.ArrayCreationExpression is array creation expression, i.e. new Char {'a'c, 'b'c}.
                    ' SyntaxKind.GetTypeExpression is a GetType expression, i.e. GetType(System.String).
                    Return True
 
                Case SyntaxKind.NameOfExpression
                    Return True
                Case Else
                    Return False
            End Select
        End Function
 
        Friend Shared Function IsConstantOptimizableLibraryMethod(compilation As VisualBasicCompilation, method As MethodSymbol) As Boolean
            Return method Is compilation.GetWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__ChrWInt32Char) OrElse
                   method Is compilation.GetWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__ChrInt32Char) OrElse
                   method Is compilation.GetWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscWCharInt32) OrElse
                   method Is compilation.GetWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscWStringInt32) OrElse
                   method Is compilation.GetWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscCharInt32) OrElse
                   method Is compilation.GetWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscStringInt32)
        End Function
 
        Friend Overrides Function BinderSpecificLookupOptions(options As LookupOptions) As LookupOptions
            ' When early binding attributes, extension methods should always be ignored.
            Return ContainingBinder.BinderSpecificLookupOptions(options) Or LookupOptions.IgnoreExtensionMethods
        End Function
 
    End Class
 
End Namespace