/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Conditional.cs
715 строк
27 KB
Tomáš Matoušek
Move some emit tests from Emit2 to Emit3 to avoid hitting UserString heap limit (#75091)
13 сен 2024, 12:01
Не верифицирован
13 сен 2024, 12:01
814c61c
Код
Авторство
О чём код?
// 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. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class AttributeTests_Conditional : WellKnownAttributesTestBase { #region Conditional Attribute Type tests #region Common Helpers private static readonly string s_commonTestSource_ConditionalAttrDefs = @" using System; using System.Diagnostics; // Applied conditional attribute [Conditional(""cond1"")] public class PreservedAppliedAttribute : Attribute { } [Conditional(""cond2"")] public class OmittedAppliedAttribute : Attribute { } // Inherited conditional attribute [Conditional(""cond3"")] public class BasePreservedInheritedAttribute : Attribute { } [Conditional(""cond4"")] public class PreservedInheritedAttribute : BasePreservedInheritedAttribute { } [Conditional(""cond5"")] public class BaseOmittedInheritedAttribute : Attribute { } public class OmittedInheritedAttribute : BaseOmittedInheritedAttribute { } // Multiple conditional attributes [Conditional(""cond6""), Conditional(""cond7"")] public class BasePreservedMultipleAttribute : Attribute { } [Conditional(""cond8"")] public class PreservedMultipleAttribute : BasePreservedMultipleAttribute { } [Conditional(""cond9"")] public class BaseOmittedMultipleAttribute : Attribute { } [Conditional(""cond10""), Conditional(""cond11"")] public class OmittedMultipleAttribute : BaseOmittedMultipleAttribute { } "; private static readonly string s_commonTestSource_ConditionalAttributesApplied = @" [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public class Z<[PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] T> { [return: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public void m([PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute]int param1) { } [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public int f; [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public int p1 { [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [return: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] get; [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [param: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] set; } [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public int p2 { [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [return: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] get { return 1; } } [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public int p3 { [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [return: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] get { return 1; } [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [param: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] set { } } [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [field: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] [method: PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public event Action e; } [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public enum E { [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] A = 1 } [PreservedAppliedAttribute, OmittedAppliedAttribute, PreservedInheritedAttribute, OmittedInheritedAttribute, PreservedMultipleAttribute, OmittedMultipleAttribute] public struct S { } public class Test { public static void Main() {} } "; private void CommonSourceValidatorForCondAttrType(ModuleSymbol module) { CommonValidatorForCondAttrType(module, isFromSource: true); } private void CommonMetadataValidatorForCondAttrType(ModuleSymbol module) { CommonValidatorForCondAttrType(module, isFromSource: false); } private void CommonValidatorForCondAttrType(ModuleSymbol module, bool isFromSource) { var attributesArrayBuilder = new List<ImmutableArray<CSharpAttributeData>>(); var classZ = module.GlobalNamespace.GetTypeMember("Z"); attributesArrayBuilder.Add(classZ.GetAttributes()); attributesArrayBuilder.Add(classZ.TypeParameters[0].GetAttributes()); var methodM = classZ.GetMember<MethodSymbol>("m"); attributesArrayBuilder.Add(methodM.GetAttributes()); attributesArrayBuilder.Add(methodM.GetReturnTypeAttributes()); var param1 = methodM.Parameters[0]; attributesArrayBuilder.Add(param1.GetAttributes()); var fieldF = classZ.GetMember<FieldSymbol>("f"); attributesArrayBuilder.Add(fieldF.GetAttributes()); var propP1 = classZ.GetMember<PropertySymbol>("p1"); attributesArrayBuilder.Add(propP1.GetAttributes()); var propGetMethod = propP1.GetMethod; attributesArrayBuilder.Add(propGetMethod.GetAttributes()); attributesArrayBuilder.Add(propGetMethod.GetReturnTypeAttributes()); var propSetMethod = propP1.SetMethod; attributesArrayBuilder.Add(propSetMethod.GetAttributes()); attributesArrayBuilder.Add(propSetMethod.Parameters[0].GetAttributes()); var propP2 = classZ.GetMember<PropertySymbol>("p2"); attributesArrayBuilder.Add(propP2.GetAttributes()); propGetMethod = propP2.GetMethod; attributesArrayBuilder.Add(propGetMethod.GetAttributes()); attributesArrayBuilder.Add(propGetMethod.GetReturnTypeAttributes()); var propP3 = classZ.GetMember<PropertySymbol>("p3"); attributesArrayBuilder.Add(propP3.GetAttributes()); propGetMethod = propP3.GetMethod; attributesArrayBuilder.Add(propGetMethod.GetAttributes()); attributesArrayBuilder.Add(propGetMethod.GetReturnTypeAttributes()); propSetMethod = propP3.SetMethod; attributesArrayBuilder.Add(propSetMethod.GetAttributes()); attributesArrayBuilder.Add(propSetMethod.Parameters[0].GetAttributes()); var eventE = classZ.GetMember<EventSymbol>("e"); attributesArrayBuilder.Add(eventE.GetAttributes()); attributesArrayBuilder.Add(eventE.AddMethod.GetAttributes()); attributesArrayBuilder.Add(eventE.RemoveMethod.GetAttributes()); if (isFromSource) { attributesArrayBuilder.Add(eventE.AssociatedField.GetAttributes()); } var enumE = module.GlobalNamespace.GetTypeMember("E"); attributesArrayBuilder.Add(enumE.GetAttributes()); var fieldA = enumE.GetMember<FieldSymbol>("A"); attributesArrayBuilder.Add(fieldA.GetAttributes()); var structS = module.GlobalNamespace.GetTypeMember("S"); attributesArrayBuilder.Add(structS.GetAttributes()); foreach (var attributes 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 var actualAttributeNames = attributes. Where(a => a.AttributeClass.Name != "CompilerGeneratedAttribute"). Select(a => a.AttributeClass.Name); if (isFromSource) { // All attributes should be present for source symbols AssertEx.SetEqual( new[] { "PreservedAppliedAttribute", "OmittedAppliedAttribute", "PreservedInheritedAttribute", "OmittedInheritedAttribute", "PreservedMultipleAttribute", "OmittedMultipleAttribute", }, actualAttributeNames); } else { // Only PreservedAppliedAttribute, PreservedInheritedAttribute, PreservedMultipleAttribute should be emitted in metadata AssertEx.SetEqual( new[] { "PreservedAppliedAttribute", "PreservedInheritedAttribute", "PreservedMultipleAttribute", }, actualAttributeNames); } } } private void TestConditionAttributeType_SameSource(string condDefs) { // Same source file string testSource = condDefs + s_commonTestSource_ConditionalAttrDefs + s_commonTestSource_ConditionalAttributesApplied; CompileAndVerify(testSource, sourceSymbolValidator: CommonSourceValidatorForCondAttrType, symbolValidator: CommonMetadataValidatorForCondAttrType, expectedOutput: ""); // Scenario to test Conditional directive stack creation during SyntaxTree.Create, see Devdiv Bug #13846 for details. CompilationUnitSyntax root = SyntaxFactory.ParseCompilationUnit(testSource); var syntaxTree = SyntaxFactory.SyntaxTree(root); var compilation = CreateCompilation(syntaxTree, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, sourceSymbolValidator: CommonSourceValidatorForCondAttrType, symbolValidator: CommonMetadataValidatorForCondAttrType, expectedOutput: ""); } private void TestConditionAttributeType_DifferentSource(string condDefsSrcFile1, string condDefsSrcFile2) { string source1 = condDefsSrcFile1 + s_commonTestSource_ConditionalAttrDefs; string source2 = condDefsSrcFile2 + @" using System; " + s_commonTestSource_ConditionalAttributesApplied; // Different source files, same compilation var testSources = new[] { source1, source2 }; CompileAndVerify(testSources, sourceSymbolValidator: CommonSourceValidatorForCondAttrType, symbolValidator: CommonMetadataValidatorForCondAttrType, expectedOutput: ""); // Different source files, different compilation var comp1 = CreateCompilation(source1); CompileAndVerify(source2, references: new[] { comp1.ToMetadataReference() }, sourceSymbolValidator: CommonSourceValidatorForCondAttrType, symbolValidator: CommonMetadataValidatorForCondAttrType, expectedOutput: ""); } #endregion #region Tests [Fact] public void TestConditionAttributeType_01() { string conditionalDefs = @" #define cond1 #define cond3 #define cond8 "; TestConditionAttributeType_SameSource(conditionalDefs); string conditionalDefsDummy = @" #define cond2 #define cond5 #define cond7 "; TestConditionAttributeType_DifferentSource(conditionalDefsDummy, conditionalDefs); } [Fact] public void TestConditionAttributeType_02() { string conditionalDefs = @" #define cond1 #define cond4 #define cond6 #define cond7 #define cond8 "; TestConditionAttributeType_SameSource(conditionalDefs); string conditionalDefsDummy = @" #define cond2 #define cond5 #undef cond1 #undef cond3 #undef cond4 #define cond9 #define cond11 "; TestConditionAttributeType_DifferentSource(conditionalDefsDummy, conditionalDefs); } [Fact] public void TestConditionAttributeType_03() { string conditionalDefs = @" #define cond1 #define cond3 #define cond4 #define cond7 #define cond8 "; TestConditionAttributeType_SameSource(conditionalDefs); string conditionalDefsDummy = @" #define cond1 #define cond2 #define cond3 #define cond4 #define cond5 "; TestConditionAttributeType_DifferentSource(conditionalDefsDummy, conditionalDefs); } [Fact] public void TestConditionAttributeType_04() { string conditionalDefs = @" #define cond1 #define cond2 #undef cond1 #undef cond3 #define cond1 #define cond3 #undef cond2 #define cond4 #undef cond3 #undef cond5 #define cond6 #undef cond7 #define cond8 #undef cond6 "; TestConditionAttributeType_SameSource(conditionalDefs); TestConditionAttributeType_DifferentSource(String.Empty, conditionalDefs); } [Fact] public void TestConditionAttributeType_05() { string conditionalDefs = @" #if cond #define cond2 #define cond5 #define cond7 #endif #define cond1 #define cond3 #define cond8 #if cond2 #undef cond1 #undef cond3 #undef cond8 #endif "; TestConditionAttributeType_SameSource(conditionalDefs); string conditionalDefsDummy = @" #define cond2 #define cond5 #define cond7 "; TestConditionAttributeType_DifferentSource(conditionalDefsDummy, conditionalDefs); } #endregion #endregion #region Conditional Method tests #region Common Helpers private static readonly string s_commonTestSource_ConditionalMethodDefs = @" using System; using System.Diagnostics; public class BaseZ { [Conditional(""cond3"")] public virtual void PreservedCalls_InheritedConditional_Method() { System.Console.WriteLine(""BaseZ.PreservedCalls_InheritedConditional_Method""); } [Conditional(""cond4"")] public virtual void OmittedCalls_InheritedConditional_Method() { System.Console.WriteLine(""BaseZ.OmittedCalls_InheritedConditional_Method""); } } public class Z: BaseZ { [Conditional(""cond1"")] public void PreservedCalls_AppliedConditional_Method() { System.Console.WriteLine(""Z.PreservedCalls_AppliedConditional_Method""); } [Conditional(""cond2"")] public void OmittedCalls_AppliedConditional_Method() { System.Console.WriteLine(""Z.OmittedCalls_AppliedConditional_Method""); } public override void PreservedCalls_InheritedConditional_Method() { System.Console.WriteLine(""Z.PreservedCalls_InheritedConditional_Method""); } public override void OmittedCalls_InheritedConditional_Method() { System.Console.WriteLine(""Z.OmittedCalls_InheritedConditional_Method""); } [Conditional(""cond5""), Conditional(""cond6"")] public void PreservedCalls_MultipleConditional_Method() { System.Console.WriteLine(""Z.PreservedCalls_MultipleConditional_Method""); } [Conditional(""cond7""), Conditional(""cond8"")] public void OmittedCalls_MultipleConditional_Method() { System.Console.WriteLine(""Z.OmittedCalls_MultipleConditional_Method""); } }"; private static readonly string s_commonTestSource_ConditionalMethodCalls = @" public class Test { public static void Main() { var 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(); } } "; private static readonly string s_commonExpectedOutput_ConditionalMethodsTest = @"Z.PreservedCalls_AppliedConditional_Method Z.PreservedCalls_InheritedConditional_Method Z.PreservedCalls_MultipleConditional_Method"; private void TestConditionMethods_SameSource(string condDefs) { // Same source file string testSource = condDefs + s_commonTestSource_ConditionalMethodDefs + s_commonTestSource_ConditionalMethodCalls; CompileAndVerify(testSource, expectedOutput: s_commonExpectedOutput_ConditionalMethodsTest); // Scenario to test Conditional directive stack creation during SyntaxTree.Create, see Devdiv Bug #13846 for details. CompilationUnitSyntax root = SyntaxFactory.ParseCompilationUnit(testSource); var syntaxTree = SyntaxFactory.SyntaxTree(root); var compilation = CreateCompilation(syntaxTree, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: s_commonExpectedOutput_ConditionalMethodsTest); } private void TestConditionMethods_DifferentSource(string condDefsSrcFile1, string condDefsSrcFile2) { string source1 = condDefsSrcFile1 + s_commonTestSource_ConditionalMethodDefs; string source2 = condDefsSrcFile2 + @" using System; " + s_commonTestSource_ConditionalMethodCalls; // Different source files, same compilation var testSources = new[] { source1, source2 }; CompileAndVerify(testSources, expectedOutput: s_commonExpectedOutput_ConditionalMethodsTest); // Different source files, different compilation var comp1 = CreateCompilation(source1, assemblyName: Guid.NewGuid().ToString()); CompileAndVerify(source2, references: new[] { comp1.ToMetadataReference() }, expectedOutput: s_commonExpectedOutput_ConditionalMethodsTest); } #endregion #region Tests [Fact] public void TestConditionMethods_01() { string conditionalDefs = @" #define cond1 #define cond3 #define cond5 "; TestConditionMethods_SameSource(conditionalDefs); string conditionalDefsDummy = @" #define cond2 #define cond4 #define cond7 "; TestConditionMethods_DifferentSource(conditionalDefsDummy, conditionalDefs); } [Fact] public void TestConditionMethods_02() { string conditionalDefs = @" #define cond1 #define cond3 #define cond5 #define cond6 "; TestConditionMethods_SameSource(conditionalDefs); string conditionalDefsDummy = @" #define cond2 #define cond5 #undef cond1 #undef cond3 #define cond8 "; TestConditionMethods_DifferentSource(conditionalDefsDummy, conditionalDefs); } [Fact] public void TestConditionMethods_03() { string conditionalDefs = @" #define cond1 #define cond3 #define cond5 #define cond7 #define cond6 #undef cond5 #undef cond7 "; TestConditionMethods_SameSource(conditionalDefs); string conditionalDefsDummy = @" #define cond1 #define cond2 #define cond3 #define cond4 #define cond5 #define cond6 #define cond7 #define cond8 "; TestConditionMethods_DifferentSource(conditionalDefsDummy, conditionalDefs); } [Fact, WorkItem(529683, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529683")] public void CondMethodInDelegateCreationExpr() { var compilation = CreateCompilation(@" using System.Diagnostics; class Test { [Conditional(""DEBUG"")] public virtual void Conditional() { } } class T1 : Test { public override void Conditional() { } } delegate void D1(); class T5 { static void Main() { T1 t1 = new T1(); D1 d1 = new D1(t1.Conditional); } } "); compilation.VerifyDiagnostics( // (27,24): error CS1618: Cannot create delegate with 'T1.Conditional()' because it has a Conditional attribute // t1.Conditional Diagnostic(ErrorCode.ERR_DelegateOnConditional, "t1.Conditional").WithArguments("T1.Conditional()")); } #endregion #endregion #region Miscellaneous tests [Fact] public void ConditionalAttributeArgument_ValidConstantMember() { string source = @" using System; using System.Diagnostics; using System.Runtime.InteropServices; [Conditional(Goo.M)] [Conditional(Bar.M)] public class Goo: Attribute { public const string M = Bar.M; public Goo([Optional][Goo]int y) {} public static void Main() { var unused = new Goo(); } } class Bar { public const string M = ""str""; } "; Func<bool, Action<ModuleSymbol>> validator = isFromSource => module => { var globalNamespace = module.GlobalNamespace; var classGoo = globalNamespace.GetMember<NamedTypeSymbol>("Goo"); Assert.True(classGoo.IsConditional); var gooCtor = classGoo.InstanceConstructors.First(); Assert.Equal(1, gooCtor.ParameterCount); var paramY = gooCtor.Parameters[0]; Assert.True(paramY.IsOptional); var attributes = paramY.GetAttributes(); if (isFromSource) { Assert.Equal(2, attributes.Length); } else { Assert.Equal(0, attributes.Length); } }; CompileAndVerify(source, symbolValidator: validator(false), sourceSymbolValidator: validator(true), expectedOutput: ""); } [Fact] public void ConditionalAttributeArgument_InvalidMember() { string source = @" using System; using System.Diagnostics; using System.Runtime.InteropServices; [Conditional(Goo.M)] [Conditional(Goo.M())] [Conditional(Bar.M)] [Conditional(Bar.M())] public class Goo: Attribute { public const string M = Bar.M; public Goo([Optional][Goo]int y) {} public static void Main() { var unused = new Goo(); } } class Bar { public static string M() { return ""str""; } } "; CreateCompilation(source).VerifyDiagnostics( // (12,33): error CS0428: Cannot convert method group 'M' to non-delegate type 'string'. Did you intend to invoke the method? // public const string M = Bar.M; Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "M").WithArguments("M", "string"), // (7,18): error CS1955: Non-invocable member 'Goo.M' cannot be used like a method. // [Conditional(Goo.M())] Diagnostic(ErrorCode.ERR_NonInvocableMemberCalled, "M").WithArguments("Goo.M"), // (8,14): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // [Conditional(Bar.M)] Diagnostic(ErrorCode.ERR_BadArgType, "Bar.M").WithArguments("1", "method group", "string"), // (9,14): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [Conditional(Bar.M())] Diagnostic(ErrorCode.ERR_BadAttributeArgument, "Bar.M()"), // (6,14): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [Conditional(Goo.M)] Diagnostic(ErrorCode.ERR_BadAttributeArgument, "Goo.M")); } [Fact] public void ConditionalAttributeArgument_Null() { var source = @"using System.Diagnostics; class Program { [Conditional(""A"")] [Conditional(null)] [Conditional(""B"")] static void Main() { } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (5,18): error CS0633: The argument to the 'Conditional' attribute must be a valid identifier // [Conditional(null)] Diagnostic(ErrorCode.ERR_BadArgumentToAttribute, "null").WithArguments("Conditional").WithLocation(5, 18)); var method = comp.GetMember<MethodSymbol>("Program.Main"); Assert.Equal(new[] { "A", null, "B" }, method.GetAppliedConditionalSymbols()); } #endregion } }