|
// 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
}
}
|