File: Attributes\AttributeTests_Conditional.vb
Web Access
Project: src\src\Compilers\VisualBasic\Test\Emit\Microsoft.CodeAnalysis.VisualBasic.Emit.UnitTests.vbproj (Microsoft.CodeAnalysis.VisualBasic.Emit.UnitTests)
' 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.Globalization
Imports System.IO
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Xml.Linq
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Roslyn.Test.Utilities
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
 
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics
    Public Class AttributeTests_Conditional
        Inherits BasicTestBase
 
#Region "Conditional Attribute Type tests"
 
#Region "Common Helpers"
        Private Shared ReadOnly s_commonTestSource_ConditionalAttrDefs As String = <![CDATA[
Imports System
Imports System.Diagnostics

' Applied conditional attribute

<Conditional("cond1")> _
Public Class PreservedAppliedAttribute
    Inherits Attribute
End Class

<Conditional("cond2")> _
Public Class OmittedAppliedAttribute
    Inherits Attribute
End Class


' Inherited conditional attribute

<Conditional("cond3_dummy")> _
Public Class BasePreservedInheritedAttribute
    Inherits Attribute
End Class
<Conditional("cond3")> _
Public Class PreservedInheritedAttribute
    Inherits BasePreservedInheritedAttribute
End Class

<Conditional("cond4")> _
Public Class BaseOmittedInheritedAttribute
    Inherits Attribute
End Class
<Conditional("cond5")> _
Public Class OmittedInheritedAttribute
    Inherits BaseOmittedInheritedAttribute
End Class

' Multiple conditional attributes

<Conditional("cond6"), Conditional("cond7"), Conditional("cond8")> _
Public Class PreservedMultipleAttribute
    Inherits Attribute
End Class

<Conditional("cond9")> _
Public Class BaseOmittedMultipleAttribute
    Inherits Attribute
End Class
<Conditional("cond10"), Conditional("cond11")> _
Public Class OmittedMultipleAttribute
    Inherits BaseOmittedMultipleAttribute
End Class


' Partially preserved applied conditional attribute
' This attribute has its conditional constant defined midway through the source file. Hence it is conditionally emitted in metadata only for some symbols.

<Conditional("condForPartiallyPreservedAppliedAttribute")> _
Public Class PartiallyPreservedAppliedAttribute
    Inherits Attribute
End Class
]]>.Value
 
        Private Shared ReadOnly s_commonTestSource_ConditionalAttributesApplied As String = <![CDATA[
<PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
Public MustInherit Class Z
    <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
    Public Function m(<PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> param1 As Integer) _
        As <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> Integer

#Const condForPartiallyPreservedAppliedAttribute = True

        Return 0
    End Function

    <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
    Public f As Integer

    <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
    Public Property p1() As <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> Integer
        <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
        Get
            Return m_p1
        End Get

#Const condForPartiallyPreservedAppliedAttribute = False

        <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
        Set(value As Integer)
            m_p1 = value
        End Set
    End Property
    Private m_p1 As Integer

    <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
    Public MustOverride ReadOnly Property p2() As <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> Integer

    <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
    Public MustOverride Property p3() As <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> Integer

    <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
    Public Event e As Action
End Class

#Const condForPartiallyPreservedAppliedAttribute = "TrueAgain"

<PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
Public Enum E
    <PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
    A = 1
End Enum

<PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute, PartiallyPreservedAppliedAttribute> _
Public Structure S
End Structure

Public Class Test
    Public Shared Sub Main()
    End Sub
End Class
]]>.Value
        Private ReadOnly _commonValidatorForCondAttrType As Func(Of Boolean, Action(Of ModuleSymbol)) =
            Function(isFromSource As Boolean) _
                Sub(m As ModuleSymbol)
 
                    ' Each Tuple indicates: <Attributes, hasPartiallyPreservedAppliedAttribute>
                    ' PartiallyPreservedAppliedAttribute has its conditional constant defined midway through the source file.
                    ' Hence this attribute is emitted in metadata only for some symbols.
                    Dim attributesArrayBuilder = ArrayBuilder(Of Tuple(Of ImmutableArray(Of VisualBasicAttributeData), Boolean)).GetInstance()
 
                    Dim classZ = m.GlobalNamespace.GetTypeMember("Z")
                    attributesArrayBuilder.Add(Tuple.Create(classZ.GetAttributes(), False))
 
                    Dim methodM = classZ.GetMember(Of MethodSymbol)("m")
                    attributesArrayBuilder.Add(Tuple.Create(methodM.GetAttributes(), False))
                    attributesArrayBuilder.Add(Tuple.Create(methodM.GetReturnTypeAttributes(), False))
                    Dim param1 = methodM.Parameters(0)
                    attributesArrayBuilder.Add(Tuple.Create(param1.GetAttributes(), False))
 
                    Dim fieldF = classZ.GetMember(Of FieldSymbol)("f")
                    attributesArrayBuilder.Add(Tuple.Create(fieldF.GetAttributes(), True))
 
                    Dim propP1 = classZ.GetMember(Of PropertySymbol)("p1")
                    attributesArrayBuilder.Add(Tuple.Create(propP1.GetAttributes(), True))
                    Dim propGetMethod = propP1.GetMethod
                    attributesArrayBuilder.Add(Tuple.Create(propGetMethod.GetAttributes(), True))
                    attributesArrayBuilder.Add(Tuple.Create(propGetMethod.GetReturnTypeAttributes(), True))
                    Dim propSetMethod = propP1.SetMethod
                    attributesArrayBuilder.Add(Tuple.Create(propSetMethod.GetAttributes(), False))
                    Assert.Equal(0, propSetMethod.GetReturnTypeAttributes().Length)
                    Assert.Equal(0, propSetMethod.Parameters(0).GetAttributes().Length)
 
                    Dim propP2 = classZ.GetMember(Of PropertySymbol)("p2")
                    attributesArrayBuilder.Add(Tuple.Create(propP2.GetAttributes(), False))
                    propGetMethod = propP2.GetMethod
                    Assert.Equal(0, propGetMethod.GetAttributes().Length)
                    attributesArrayBuilder.Add(Tuple.Create(propGetMethod.GetReturnTypeAttributes(), False))
 
                    Dim propP3 = classZ.GetMember(Of PropertySymbol)("p3")
                    attributesArrayBuilder.Add(Tuple.Create(propP3.GetAttributes(), False))
                    propGetMethod = propP3.GetMethod
                    Assert.Equal(0, propGetMethod.GetAttributes().Length)
                    attributesArrayBuilder.Add(Tuple.Create(propGetMethod.GetReturnTypeAttributes(), False))
                    propSetMethod = propP3.SetMethod
                    Assert.Equal(0, propSetMethod.GetAttributes().Length)
                    Assert.Equal(0, propSetMethod.GetReturnTypeAttributes().Length)
                    Assert.Equal(0, propSetMethod.Parameters(0).GetAttributes().Length)
 
                    Dim eventE = classZ.GetMember(Of EventSymbol)("e")
                    attributesArrayBuilder.Add(Tuple.Create(eventE.GetAttributes(), False))
                    If isFromSource Then
                        Assert.Equal(0, eventE.AssociatedField.GetAttributes().Length)
                        Assert.Equal(0, eventE.AddMethod.GetAttributes().Length)
                        Assert.Equal(0, eventE.RemoveMethod.GetAttributes().Length)
                    Else
                        AssertEx.Equal({"CompilerGeneratedAttribute"}, GetAttributeNames(eventE.AddMethod.GetAttributes()))
                        AssertEx.Equal({"CompilerGeneratedAttribute"}, GetAttributeNames(eventE.RemoveMethod.GetAttributes()))
                    End If
                    Assert.Equal(0, eventE.AddMethod.GetReturnTypeAttributes().Length)
                    Assert.Equal(0, eventE.RemoveMethod.GetReturnTypeAttributes().Length)
 
                    Dim enumE = m.GlobalNamespace.GetTypeMember("E")
                    attributesArrayBuilder.Add(Tuple.Create(enumE.GetAttributes(), True))
 
                    Dim fieldA = enumE.GetMember(Of FieldSymbol)("A")
                    attributesArrayBuilder.Add(Tuple.Create(fieldA.GetAttributes(), True))
 
                    Dim structS = m.GlobalNamespace.GetTypeMember("S")
                    attributesArrayBuilder.Add(Tuple.Create(structS.GetAttributes(), True))
 
                    For Each tup In attributesArrayBuilder
                        ' PreservedAppliedAttribute and OmittedAppliedAttribute have applied conditional attributes, such that
                        ' (a) PreservedAppliedAttribute is conditionally applied to symbols
                        ' (b) OmittedAppliedAttribute is conditionally NOT applied to symbols
 
                        ' PreservedInheritedAttribute and OmittedInheritedAttribute have inherited conditional attributes, such that
                        ' (a) PreservedInheritedAttribute is conditionally applied to symbols
                        ' (b) OmittedInheritedAttribute is conditionally NOT applied to symbols
 
                        ' PreservedMultipleAttribute and OmittedMultipleAttribute have multiple applied/inherited conditional attributes, such that
                        ' (a) PreservedMultipleAttribute is conditionally applied to symbols
                        ' (b) OmittedMultipleAttribute is conditionally NOT applied to symbols
 
                        ' PartiallyPreservedAppliedAttribute has its conditional constant defined midway through the source file.
                        ' Hence this attribute is emitted in metadata only for some symbols.
 
                        Dim attributesArray As ImmutableArray(Of VisualBasicAttributeData) = tup.Item1
                        Dim actualAttributeNames = GetAttributeNames(attributesArray)
 
                        If isFromSource Then
                            ' All attributes should be present for source symbols
                            AssertEx.SetEqual({"PreservedAppliedAttribute",
                                               "OmittedAppliedAttribute",
                                               "PreservedInheritedAttribute",
                                               "OmittedInheritedAttribute",
                                               "PreservedMultipleAttribute",
                                               "OmittedMultipleAttribute",
                                               "PartiallyPreservedAppliedAttribute"}, actualAttributeNames)
                        Else
                            Dim hasPartiallyPreservedAppliedAttribute = tup.Item2
 
                            Dim expectedAttributeNames As String()
 
                            If Not hasPartiallyPreservedAppliedAttribute Then
                                ' Only PreservedAppliedAttribute, PreservedInheritedAttribute, PreservedMultipleAttribute should be emitted in metadata
                                expectedAttributeNames = {"PreservedAppliedAttribute",
                                                          "PreservedInheritedAttribute",
                                                          "PreservedMultipleAttribute"}
                            Else
                                ' PartiallyPreservedAppliedAttribute must also be emitted in metadata
                                expectedAttributeNames = {"PreservedAppliedAttribute",
                                                          "PreservedInheritedAttribute",
                                                          "PreservedMultipleAttribute",
                                                          "PartiallyPreservedAppliedAttribute"}
                            End If
 
                            AssertEx.SetEqual(expectedAttributeNames, actualAttributeNames)
                        End If
                    Next
 
                    attributesArrayBuilder.Free()
                End Sub
 
        Private Sub TestConditionAttributeType_SameSource(condDefs As String, preprocessorSymbols As ImmutableArray(Of KeyValuePair(Of String, Object)))
            ' Same source file
            Debug.Assert(Not preprocessorSymbols.IsDefault)
            Dim parseOpts = VisualBasicParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbols)
            Dim testSource As String = condDefs & s_commonTestSource_ConditionalAttrDefs & s_commonTestSource_ConditionalAttributesApplied
            Dim compilation = CreateCompilationWithMscorlib40({Parse(testSource, parseOpts)}, options:=TestOptions.ReleaseExe)
            CompileAndVerify(compilation, sourceSymbolValidator:=_commonValidatorForCondAttrType(True), symbolValidator:=_commonValidatorForCondAttrType(False), expectedOutput:="")
        End Sub
 
        Private Sub TestConditionAttributeType_SameSource(condDefs As String)
            TestConditionAttributeType_SameSource(condDefs, ImmutableArray.Create(Of KeyValuePair(Of String, Object))())
        End Sub
 
        Private Sub TestConditionAttributeType_DifferentSource(condDefsSrcFile1 As String, condDefsSrcFile2 As String)
            TestConditionAttributeType_DifferentSource(condDefsSrcFile1, ImmutableArray.Create(Of KeyValuePair(Of String, Object))(), condDefsSrcFile2, ImmutableArray.Create(Of KeyValuePair(Of String, Object))())
        End Sub
 
        Private Sub TestConditionAttributeType_DifferentSource(condDefsSrcFile1 As String,
                                                               preprocessorSymbolsSrcFile1 As ImmutableArray(Of KeyValuePair(Of String, Object)),
                                                               condDefsSrcFile2 As String,
                                                               preprocessorSymbolsSrcFile2 As ImmutableArray(Of KeyValuePair(Of String, Object)))
            Dim source1 As String = condDefsSrcFile1 & s_commonTestSource_ConditionalAttrDefs
            Dim source2 As String = condDefsSrcFile2 & <![CDATA[
Imports System
Imports System.Diagnostics
]]>.Value & s_commonTestSource_ConditionalAttributesApplied
 
            Debug.Assert(Not preprocessorSymbolsSrcFile1.IsDefault)
            Dim parseOpts1 = VisualBasicParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbolsSrcFile1)
            Debug.Assert(Not preprocessorSymbolsSrcFile2.IsDefault)
            Dim parseOpts2 = VisualBasicParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbolsSrcFile2)
 
            ' Different source files, same compilation
            Dim comp = CreateCompilationWithMscorlib40({Parse(source1, parseOpts1), Parse(source2, parseOpts2)}, options:=TestOptions.ReleaseExe)
            CompileAndVerify(comp, sourceSymbolValidator:=_commonValidatorForCondAttrType(True), symbolValidator:=_commonValidatorForCondAttrType(False), expectedOutput:="")
 
            ' Different source files, different compilation
            Dim comp1 = CreateCompilationWithMscorlib40({Parse(source1, parseOpts1)}, options:=TestOptions.ReleaseDll)
            Dim comp2 = VisualBasicCompilation.Create("comp2", {Parse(source2, parseOpts2)}, {MscorlibRef, New VisualBasicCompilationReference(comp1)}, options:=TestOptions.ReleaseExe)
            CompileAndVerify(comp2, sourceSymbolValidator:=_commonValidatorForCondAttrType(True), symbolValidator:=_commonValidatorForCondAttrType(False), expectedOutput:="")
        End Sub
#End Region
 
#Region "Tests"
        <Fact>
        Public Sub TestConditionAttributeType_01_SourceDefines()
            Dim conditionalDefs As String = <![CDATA[
#Const cond1 = 1
#Const cond3 = ""
#Const cond6 = True
 ]]>.Value
 
            TestConditionAttributeType_SameSource(conditionalDefs)
 
            Dim conditionalDefsDummy As String = <![CDATA[
#Const cond2 = 1
#Const cond5 = ""
#Const cond7 = True
 ]]>.Value
            TestConditionAttributeType_DifferentSource(conditionalDefsDummy, conditionalDefs)
        End Sub
 
        <Fact>
        Public Sub TestConditionAttributeType_01_CommandLineDefines()
            Dim preprocessorSymbols = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond1", 1),
                                                                                               New KeyValuePair(Of String, Object)("cond3", ""),
                                                                                               New KeyValuePair(Of String, Object)("cond6", True))
            TestConditionAttributeType_SameSource(condDefs:="", preprocessorSymbols:=preprocessorSymbols)
 
            Dim preprocessorSymbolsDummy = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond2", 1),
                                                                                                    New KeyValuePair(Of String, Object)("cond5", ""),
                                                                                                    New KeyValuePair(Of String, Object)("cond7", True))
            TestConditionAttributeType_DifferentSource(condDefsSrcFile1:="", preprocessorSymbolsSrcFile1:=preprocessorSymbolsDummy, condDefsSrcFile2:="", preprocessorSymbolsSrcFile2:=preprocessorSymbols)
        End Sub
 
        <Fact>
        Public Sub TestConditionAttributeType_02_SourceDefines()
            Dim conditionalDefs As String = <![CDATA[
#Const cond1 = 1
#Const cond2 = 1.0  ' Decimal type value is not considered for CC constants.
#Const cond3 = ""
#Const cond4 = True     ' Conditional attributes are not inherited from base type.
#Const cond5 = 1
#Const cond5 = Nothing  ' The last definition holds for CC constants.
#Const cond6 = True
#Const cond7 = 0  ' One of the conditional symbol is zero, but other conditional symbols for the attribute type are defined.
#Const cond8 = 2 ' Multiple conditional symbols defined.
 ]]>.Value
 
            TestConditionAttributeType_SameSource(conditionalDefs)
 
            Dim conditionalDefsDummy As String = <![CDATA[
#Const cond2 = 1
#Const cond3_dummy = 0
#Const cond5 = ""
#Const cond7 = True
#Const cond8 = True
#Const cond9 = True
#Const cond10 = True
#Const cond11 = True
 ]]>.Value
            TestConditionAttributeType_DifferentSource(conditionalDefsDummy, conditionalDefs)
        End Sub
 
        <Fact>
        Public Sub TestConditionAttributeType_02_CommandLineDefines()
            ' Mix and match source and command line defines.
            Dim preprocessorSymbols = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond1", 1),
                                                                                               New KeyValuePair(Of String, Object)("cond2", 1.0),
                                                                                               New KeyValuePair(Of String, Object)("cond3", ""),
                                                                                               New KeyValuePair(Of String, Object)("cond4", True),
                                                                                               New KeyValuePair(Of String, Object)("cond5", 1))
            Dim conditionalDefs As String = <![CDATA[
#Const cond5 = Nothing  ' Source definition for CC constants overrides command line /define definitions.
#Const cond6 = True ' Mix match source and command line defines.
#Const cond7 = 0  ' One of the conditional symbol is zero, but other conditional symbols for the attribute type are defined.
#Const cond8 = 2 ' Multiple conditional symbols defined.
 ]]>.Value
 
            TestConditionAttributeType_SameSource(conditionalDefs, preprocessorSymbols:=preprocessorSymbols)
 
            ' Mix and match source and command line defines.
            Dim preprocessorSymbolsDummy = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond2", 1),
                                                                                                    New KeyValuePair(Of String, Object)("cond3_dummy", 1))
            Dim conditionalDefsDummy As String = <![CDATA[
#Const cond5 = ""
#Const cond7 = True
#Const cond8 = True
#Const cond9 = True
#Const cond10 = True
#Const cond11 = True
 ]]>.Value
            TestConditionAttributeType_DifferentSource(conditionalDefsDummy, preprocessorSymbolsDummy, conditionalDefs, preprocessorSymbols)
        End Sub
 
        <Fact>
        Public Sub TestNestedTypeMember()
            Dim source =
<compilation>
    <file name="a.vb"><![CDATA[
Imports System
Imports System.Diagnostics

<Conditional(Outer.Nested.ConstStr)> _
<Outer> _
Class Outer
	Inherits Attribute
	Public Class Nested
		Public Const ConstStr As String = "str"
	End Class
End Class
 ]]>
    </file>
</compilation>
 
            CompileAndVerify(source)
        End Sub
 
#End Region
 
#End Region
 
#Region "Conditional Method tests"
 
#Region "Common Helpers"
        Private Shared ReadOnly s_commonTestSource_ConditionalMethodDefs As String = <![CDATA[
    Imports System
    Imports System.Diagnostics

    Public Class BaseZ
        <Conditional("cond3_base")> _
        Public Overridable Sub PreservedCalls_InheritedConditional_Method()
            System.Console.WriteLine("BaseZ.PreservedCalls_InheritedConditional_Method")
        End Sub

        <Conditional("cond4_base")> _
        Public Overridable Sub OmittedCalls_InheritedConditional_Method()
            System.Console.WriteLine("BaseZ.OmittedCalls_InheritedConditional_Method")
        End Sub
    End Class

    Public Interface I
        ' Conditional attributes are ignored for interface methods, but respected for implementing methods.
        <Conditional("dummy")>
        Sub PartiallyPreservedCalls_Interface_Method()
    End Interface

    Public Class Z
        Inherits BaseZ
        Implements I

        <Conditional("cond1")> _
        Public Sub PreservedCalls_AppliedConditional_Method()
            System.Console.WriteLine("Z.PreservedCalls_AppliedConditional_Method")
        End Sub

        <Conditional("cond2")> _
        Public Sub OmittedCalls_AppliedConditional_Method()
            System.Console.WriteLine("Z.OmittedCalls_AppliedConditional_Method")
        End Sub

        ' Conditional symbols are not inherited by overriding methods in VB
        <Conditional("cond3")> _
        Public Overrides Sub PreservedCalls_InheritedConditional_Method()
            System.Console.WriteLine("Z.PreservedCalls_InheritedConditional_Method")
        End Sub

    #Const cond4_base = "Conditional symbols are not inherited by overriding methods in VB"
        <Conditional("cond4")> _
        Public Overrides Sub OmittedCalls_InheritedConditional_Method()
            System.Console.WriteLine("Z.OmittedCalls_InheritedConditional_Method")
        End Sub

        <Conditional("cond5"), Conditional("cond6")> _
        Public Sub PreservedCalls_MultipleConditional_Method()
            System.Console.WriteLine("Z.PreservedCalls_MultipleConditional_Method")
        End Sub

        <Conditional("cond7"), Conditional("cond8")> _
        Public Sub OmittedCalls_MultipleConditional_Method()
            System.Console.WriteLine("Z.OmittedCalls_MultipleConditional_Method")
        End Sub

        ' Conditional attributes are ignored for interface methods, but respected for implementing methods.
        <Conditional("cond9")>
        Public Sub PartiallyPreservedCalls_Interface_Method() Implements I.PartiallyPreservedCalls_Interface_Method
            System.Console.WriteLine("Z.PartiallyPreservedCalls_Interface_Method")
        End Sub

        ' Conditional attributes are ignored for functions
        <Conditional("cond10")>
        Public Function PreservedCalls_Function() As Integer
            System.Console.WriteLine("Z.PreservedCalls_Function")
            Return 0
        End Function

        <Conditional(""), Conditional(Nothing)> _
        Public Sub OmittedCalls_AlwaysFalseConditional_Method()
            System.Console.WriteLine("Z.OmittedCalls_AlwaysFalseConditional_Method")
        End Sub

        <Conditional("condForPartiallyPreservedAppliedAttribute")>
        Public Sub PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method(i As Integer)
            System.Console.WriteLine("Z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method" & i)
        End Sub
    End Class
    ]]>.Value
 
        Private Shared ReadOnly s_commonTestSource_ConditionalMethodCalls As String = <![CDATA[
    Module Module1
        Public Sub Main()
            Dim z = New Z()
            z.PreservedCalls_AppliedConditional_Method()
            z.OmittedCalls_AppliedConditional_Method()
            z.PreservedCalls_InheritedConditional_Method()
            z.OmittedCalls_InheritedConditional_Method()
            z.PreservedCalls_MultipleConditional_Method()
            z.OmittedCalls_MultipleConditional_Method()
            z.OmittedCalls_AlwaysFalseConditional_Method()
            z.PartiallyPreservedCalls_Interface_Method() ' Omitted
            DirectCast(z, I).PartiallyPreservedCalls_Interface_Method() ' Preserved
            Console.WriteLine(z.PreservedCalls_Function())

            ' Second and fourth calls are preserved, first, third and fifth calls are omitted.
            z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method(1)
    # Const condForPartiallyPreservedAppliedAttribute = True
            z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method(2)
    # Const condForPartiallyPreservedAppliedAttribute = 0
            z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method(3)
    # Const condForPartiallyPreservedAppliedAttribute = "TrueAgain"
            z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method(4)
    # Const condForPartiallyPreservedAppliedAttribute = Nothing
            z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method(5)
        End Sub
    End Module
    ]]>.Value
 
        Private Shared ReadOnly s_commonExpectedOutput_ConditionalMethodsTest As String =
            "Z.PreservedCalls_AppliedConditional_Method" & Environment.NewLine &
            "Z.PreservedCalls_InheritedConditional_Method" & Environment.NewLine &
            "Z.PreservedCalls_MultipleConditional_Method" & Environment.NewLine &
            "Z.PartiallyPreservedCalls_Interface_Method" & Environment.NewLine &
            "Z.PreservedCalls_Function" & Environment.NewLine &
            "0" & Environment.NewLine &
            "Z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method2" & Environment.NewLine &
            "Z.PartiallyPreservedCalls_PartiallyPreservedAppliedAttribute_Method4" & Environment.NewLine
 
        Private Sub TestConditionalMethod_SameSource(condDefs As String)
            TestConditionalMethod_SameSource(condDefs, ImmutableArray.Create(Of KeyValuePair(Of String, Object))())
        End Sub
 
        Private Sub TestConditionalMethod_SameSource(condDefs As String, preprocessorSymbols As ImmutableArray(Of KeyValuePair(Of String, Object)))
            ' Same source file
            Debug.Assert(Not preprocessorSymbols.IsDefault)
            Dim parseOpts = VisualBasicParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbols)
            Dim testSource As String = condDefs & s_commonTestSource_ConditionalMethodDefs & s_commonTestSource_ConditionalMethodCalls
            Dim comp = VisualBasicCompilation.Create(GetUniqueName(), {Parse(testSource, parseOpts)}, {MscorlibRef, SystemCoreRef, MsvbRef})
            CompileAndVerify(comp, expectedOutput:=s_commonExpectedOutput_ConditionalMethodsTest)
        End Sub
 
        Private Sub TestConditionalMethod_DifferentSource(condDefsSrcFile1 As String, condDefsSrcFile2 As String)
            TestConditionalMethod_DifferentSource(condDefsSrcFile1, ImmutableArray.Create(Of KeyValuePair(Of String, Object))(), condDefsSrcFile2, ImmutableArray.Create(Of KeyValuePair(Of String, Object))())
        End Sub
 
        Private Sub TestConditionalMethod_DifferentSource(condDefsSrcFile1 As String,
                                                          preprocessorSymbolsSrcFile1 As ImmutableArray(Of KeyValuePair(Of String, Object)),
                                                          condDefsSrcFile2 As String,
                                                          preprocessorSymbolsSrcFile2 As ImmutableArray(Of KeyValuePair(Of String, Object)))
            Dim source1 As String = condDefsSrcFile1 & s_commonTestSource_ConditionalMethodDefs
            Dim source2 As String = condDefsSrcFile2 & <![CDATA[
Imports System
Imports System.Diagnostics
]]>.Value & s_commonTestSource_ConditionalMethodCalls
 
            Debug.Assert(Not preprocessorSymbolsSrcFile1.IsDefault)
            Dim parseOpts1 = VisualBasicParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbolsSrcFile1)
            Debug.Assert(Not preprocessorSymbolsSrcFile2.IsDefault)
            Dim parseOpts2 = VisualBasicParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbolsSrcFile2)
 
            ' Different source files, same compilation
            Dim comp = VisualBasicCompilation.Create(GetUniqueName(), {Parse(source1, parseOpts1), Parse(source2, parseOpts2)}, {MscorlibRef, MsvbRef}, TestOptions.ReleaseExe)
            CompileAndVerify(comp, expectedOutput:=s_commonExpectedOutput_ConditionalMethodsTest)
 
            ' Different source files, different compilation
            Dim comp1 = VisualBasicCompilation.Create(GetUniqueName(), {Parse(source1, parseOpts1)}, {MscorlibRef, MsvbRef}, TestOptions.ReleaseDll)
            Dim comp2 = VisualBasicCompilation.Create(GetUniqueName(), {Parse(source2, parseOpts2)}, {MscorlibRef, MsvbRef, comp1.ToMetadataReference()}, TestOptions.ReleaseExe)
            CompileAndVerify(comp2, expectedOutput:=s_commonExpectedOutput_ConditionalMethodsTest)
        End Sub
#End Region
 
#Region "Tests"
        <Fact>
        Public Sub TestConditionalMethod_01_SourceDefines()
            Dim conditionalDefs As String = <![CDATA[
#Const cond1 = 1
#Const cond3 = ""
#Const cond5 = True
 ]]>.Value
 
            TestConditionalMethod_SameSource(conditionalDefs)
 
            Dim conditionalDefsDummy As String = <![CDATA[
#Const cond2 = 1
#Const cond5 = ""
#Const cond7 = True
 ]]>.Value
            TestConditionalMethod_DifferentSource(conditionalDefsDummy, conditionalDefs)
        End Sub
 
        <Fact>
        Public Sub TestConditionalMethod_01_CommandLineDefines()
            Dim preprocessorSymbols = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond1", 1),
                                                                                               New KeyValuePair(Of String, Object)("cond3", ""),
                                                                                               New KeyValuePair(Of String, Object)("cond5", True))
            TestConditionalMethod_SameSource(condDefs:="", preprocessorSymbols:=preprocessorSymbols)
 
            Dim preprocessorSymbolsDummy = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond2", 1),
                                                                                                    New KeyValuePair(Of String, Object)("cond5", ""),
                                                                                                    New KeyValuePair(Of String, Object)("cond7", True))
 
            TestConditionalMethod_DifferentSource(condDefsSrcFile1:="", preprocessorSymbolsSrcFile1:=preprocessorSymbolsDummy, condDefsSrcFile2:="", preprocessorSymbolsSrcFile2:=preprocessorSymbols)
        End Sub
 
        <Fact>
        Public Sub TestConditionalMethod_02_SourceDefines()
            Dim conditionalDefs As String = <![CDATA[
#Const cond1 = 1
#Const cond2 = 1.0  ' Decimal type value is not considered for CC constants.
#Const cond3 = ""
#Const cond4_base = True     ' Conditional attributes are not inherited from base type.
#Const cond5 = 1
#Const cond5 = 0  ' One of the conditional symbol is zero, but other conditional symbols for the attribute type are defined.
#Const cond6 = True
#Const cond7 = 0  
#Const cond3 = True ' The last definition holds for CC constants.
 ]]>.Value
 
            TestConditionalMethod_SameSource(conditionalDefs)
 
            Dim conditionalDefsDummy As String = <![CDATA[
#Const cond2 = 1
#Const cond3_dummy = 0
#Const cond5 = ""
#Const cond7 = True
#Const cond8 = True
#Const cond9 = True
#Const cond10 = True
#Const cond11 = True
 ]]>.Value
            TestConditionalMethod_DifferentSource(conditionalDefsDummy, conditionalDefs)
        End Sub
 
        <Fact>
        Public Sub TestConditionalMethod_02_CommandLineDefines()
            ' Mix and match source and command line defines.
            Dim preprocessorSymbols = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond1", 1),
                                                                                               New KeyValuePair(Of String, Object)("cond2", 1.0),
                                                                                               New KeyValuePair(Of String, Object)("cond3", ""),
                                                                                               New KeyValuePair(Of String, Object)("cond4_base", True),
                                                                                               New KeyValuePair(Of String, Object)("cond5", 1))
            Dim conditionalDefs As String = <![CDATA[
#Const cond5 = 0  ' One of the conditional symbol is zero, but other conditional symbols for the attribute type are defined.
#Const cond6 = True
#Const cond7 = 0  
#Const cond3 = True ' The last definition holds for CC constants.
 ]]>.Value
 
            TestConditionalMethod_SameSource(conditionalDefs, preprocessorSymbols)
 
            ' Mix and match source and command line defines.
            Dim preprocessorSymbolsDummy = ImmutableArray.Create(Of KeyValuePair(Of String, Object))(New KeyValuePair(Of String, Object)("cond2", 1),
                                                                                                    New KeyValuePair(Of String, Object)("cond3_dummy", 0),
                                                                                                    New KeyValuePair(Of String, Object)("cond5", True))
            Dim conditionalDefsDummy As String = <![CDATA[
#Const cond7 = True
#Const cond8 = True
#Const cond9 = True
#Const cond10 = True
#Const cond11 = True
 ]]>.Value
            TestConditionalMethod_DifferentSource(conditionalDefsDummy, preprocessorSymbolsDummy, conditionalDefs, preprocessorSymbols)
        End Sub
 
        <WorkItem(546089, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546089")>
        <Fact>
        Public Sub CaseInsensitivityTest()
            Dim source =
                <compilation>
                    <file name="a.vb">
Imports System
 
Module Test
    &lt;System.Diagnostics.Conditional("VAR4")&gt; 
    Sub Sub1()
        Console.WriteLine("Sub1 Called")
    End Sub
 
    Sub Main()
#Const var4 = True
        Sub1()
    End Sub
 
End Module
                    </file>
                </compilation>
 
            CompileAndVerify(source, expectedOutput:=<![CDATA[Sub1 Called]]>)
        End Sub
 
        <WorkItem(546089, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546089")>
        <Fact>
        Public Sub CaseInsensitivityTest_02()
            Dim source =
                <compilation>
                    <file name="a.vb">
Imports System
 
Module Test
    &lt;System.Diagnostics.Conditional("VAR4")&gt; 
    Sub Sub1()
        Console.WriteLine("Sub1 Called")
    End Sub
 
#Const VAR4 = False
    Sub Main()
#Const var4 = True
        Sub1()
    End Sub
 
End Module
                    </file>
                </compilation>
 
            CompileAndVerify(source, expectedOutput:=<![CDATA[Sub1 Called]]>)
        End Sub
 
        <WorkItem(546094, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546094")>
        <Fact>
        Public Sub ConditionalAttributeOnPropertySetter()
            Dim source =
                <compilation>
                    <file name="a.vb">
Imports System
 
Class TestClass
    WriteOnly Property goo() As String
        &lt;Diagnostics.Conditional("N")&gt;
        Set(ByVal Value As String)
            Console.WriteLine("Property Called")
        End Set
    End Property
End Class
 
Module M1
    Sub Main()
        Dim t As New TestClass()
        t.goo = "abds"
    End Sub
End Module
 
                    </file>
                </compilation>
 
            CompileAndVerify(source, expectedOutput:=<![CDATA[Property Called]]>)
        End Sub
#End Region
 
        <WorkItem(1003274, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1003274")>
        <Fact>
        Public Sub ConditionalAttributeInNetModule()
            Const source = "
Imports System.Diagnostics
 
Class C
    Sub M()
        N1()
        N2()
    End Sub
 
    <Conditional(""Defined"")>
    Sub N1()
    End Sub
 
    <Conditional(""Undefined"")>
    Sub N2()
    End Sub
End Class
"
            Dim parseOptions As New VisualBasicParseOptions(preprocessorSymbols:={New KeyValuePair(Of String, Object)("Defined", True)})
            Dim comp = CreateCompilationWithMscorlib40({VisualBasicSyntaxTree.ParseText(source, parseOptions)}, options:=TestOptions.ReleaseModule)
            CompileAndVerify(comp, verify:=Verification.Fails).VerifyIL("C.M", "
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""Sub C.N1()""
  IL_0006:  ret
}
")
        End Sub
 
#End Region
 
    End Class
End Namespace