|
// 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.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
/// <summary>
/// NYI: PEVerify currently fails for netmodules with error: "The module X was expected to contain an assembly manifest".
/// Verification was disabled for net modules for now. Add it back once module support has been added.
/// See tests having verify: !outputKind.IsNetModule()
/// https://github.com/dotnet/roslyn/issues/23475
/// </summary>
public class AttributeTests_Synthesized : WellKnownAttributesTestBase
{
#region Theory Data
public static IEnumerable<object[]> OptimizationLevelTheoryData
{
get
{
foreach (var level in Enum.GetValues(typeof(OptimizationLevel)))
{
yield return new object[] { level };
}
}
}
public static IEnumerable<object[]> FullMatrixTheoryData
{
get
{
foreach (var kind in Enum.GetValues(typeof(OutputKind)))
{
foreach (var level in Enum.GetValues(typeof(OptimizationLevel)))
{
yield return new object[] { kind, level };
}
}
}
}
#endregion
#region Helpers
private void VerifyCompilationRelaxationsAttribute(CSharpAttributeData attribute, bool isSynthesized)
{
Assert.Equal("System.Runtime.CompilerServices.CompilationRelaxationsAttribute", attribute.AttributeClass.ToTestDisplayString());
Assert.Equal("System.Int32", attribute.AttributeConstructor.Parameters.Single().TypeWithAnnotations.ToTestDisplayString());
Assert.Empty(attribute.CommonNamedArguments);
int expectedArgValue = isSynthesized ? (int)CompilationRelaxations.NoStringInterning : 0;
Assert.Equal(1, attribute.CommonConstructorArguments.Length);
attribute.VerifyValue(0, TypedConstantKind.Primitive, expectedArgValue);
}
private void VerifyRuntimeCompatibilityAttribute(CSharpAttributeData attribute, bool isSynthesized)
{
Assert.Equal("System.Runtime.CompilerServices.RuntimeCompatibilityAttribute", attribute.AttributeClass.ToTestDisplayString());
Assert.Empty(attribute.AttributeConstructor.Parameters);
Assert.Empty(attribute.CommonConstructorArguments);
if (isSynthesized)
{
Assert.Equal(1, attribute.CommonNamedArguments.Length);
attribute.VerifyNamedArgumentValue<bool>(0, "WrapNonExceptionThrows", TypedConstantKind.Primitive, true);
}
else
{
Assert.Equal(0, attribute.CommonNamedArguments.Length);
}
}
private void VerifyDebuggableAttribute(CSharpAttributeData attribute, OptimizationLevel optimizations, bool isSynthesized)
{
Assert.Equal("System.Diagnostics.DebuggableAttribute", attribute.AttributeClass.ToTestDisplayString());
Assert.Equal("System.Diagnostics.DebuggableAttribute.DebuggingModes", attribute.AttributeConstructor.Parameters.Single().TypeWithAnnotations.ToTestDisplayString());
Assert.Empty(attribute.CommonNamedArguments);
Assert.Equal(1, attribute.CommonConstructorArguments.Length);
var expectedDebuggingMode = DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints;
if (isSynthesized && optimizations == OptimizationLevel.Debug)
{
expectedDebuggingMode |=
DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue;
}
attribute.VerifyValue(0, TypedConstantKind.Enum, (int)expectedDebuggingMode);
}
#endregion
#region CompilerGeneratedAttribute, DebuggerBrowsableAttribute, DebuggerStepThroughAttribute, DebuggerDisplayAttribute
[Fact]
[WorkItem(546632, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546632")]
public void PrivateImplementationDetails()
{
string source = @"
class C
{
int[] a = new[] { 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9, };
}
";
var reference = CreateCompilation(source).EmitToImageReference();
var comp = CreateEmptyCompilation("", new[] { reference }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal));
var pid = (NamedTypeSymbol)comp.GlobalNamespace.GetMembers().Where(s => s.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal)).Single();
var expectedAttrs = new[] { "CompilerGeneratedAttribute" };
var actualAttrs = GetAttributeNames(pid.GetAttributes());
AssertEx.SetEqual(expectedAttrs, actualAttrs);
}
[Fact]
[WorkItem(546958, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546958")]
public void FixedSizeBuffers()
{
string source = @"
unsafe struct S
{
public fixed char C[5];
}
";
var reference = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).EmitToImageReference();
var comp = CreateEmptyCompilation("", new[] { reference }, options: TestOptions.UnsafeReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal));
var s = (NamedTypeSymbol)comp.GlobalNamespace.GetMembers("S").Single();
var bufferType = (NamedTypeSymbol)s.GetMembers().Where(t => t.Name == "<C>e__FixedBuffer").Single();
var expectedAttrs = new[] { "CompilerGeneratedAttribute", "UnsafeValueTypeAttribute" };
var actualAttrs = GetAttributeNames(bufferType.GetAttributes());
AssertEx.SetEqual(expectedAttrs, actualAttrs);
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
[WorkItem(546927, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546927")]
public void BackingFields_Property(OptimizationLevel optimizationLevel)
{
string source = @"
using System;
class Test
{
public string MyProp { get; set; }
public event Func<int> MyEvent;
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(source, options: options, symbolValidator: module =>
{
var peModule = (PEModuleSymbol)module;
var type = peModule.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
var property = type.GetMember<PEFieldSymbol>(GeneratedNames.MakeBackingFieldName("MyProp"));
Verify(property.Handle);
var eventField = (PEFieldSymbol)type.GetMember<PEEventSymbol>("MyEvent").AssociatedField;
Verify(eventField.Handle);
void Verify(EntityHandle token)
{
var attributes = peModule.GetCustomAttributesForToken(token);
if (optimizationLevel == OptimizationLevel.Debug)
{
Assert.Equal(2, attributes.Length);
Assert.Equal("CompilerGeneratedAttribute", attributes[0].AttributeClass.Name);
Assert.Equal("DebuggerBrowsableAttribute", attributes[1].AttributeClass.Name);
Assert.Equal(DebuggerBrowsableState.Never, (DebuggerBrowsableState)attributes[1].ConstructorArguments.Single().Value);
}
else
{
Assert.Equal("CompilerGeneratedAttribute", attributes.Single().AttributeClass.Name);
}
}
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
[WorkItem(546927, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546927")]
public void Accessors(OptimizationLevel optimizationLevel)
{
string source = @"
using System;
abstract class C
{
public int P { get; set; }
public abstract int Q { get; set; }
public event Func<int> E;
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(source, options: options, symbolValidator: module =>
{
var peModule = (PEModuleSymbol)module;
var c = peModule.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
var p = c.GetMember<PropertySymbol>("P");
Assert.Equal("CompilerGeneratedAttribute", peModule.GetCustomAttributesForToken(((PEMethodSymbol)p.GetMethod).Handle).Single().AttributeClass.Name);
Assert.Equal("CompilerGeneratedAttribute", peModule.GetCustomAttributesForToken(((PEMethodSymbol)p.SetMethod).Handle).Single().AttributeClass.Name);
// no attributes on abstract property accessors
var q = c.GetMember<PropertySymbol>("Q");
Assert.Empty(peModule.GetCustomAttributesForToken(((PEMethodSymbol)q.GetMethod).Handle));
Assert.Empty(peModule.GetCustomAttributesForToken(((PEMethodSymbol)q.SetMethod).Handle));
var e = c.GetMember<EventSymbol>("E");
Assert.Equal("CompilerGeneratedAttribute", peModule.GetCustomAttributesForToken(((PEMethodSymbol)e.AddMethod).Handle).Single().AttributeClass.Name);
Assert.Equal("CompilerGeneratedAttribute", peModule.GetCustomAttributesForToken(((PEMethodSymbol)e.RemoveMethod).Handle).Single().AttributeClass.Name);
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void Lambdas(OptimizationLevel optimizationLevel)
{
string source = @"
using System;
class C
{
void Goo()
{
int a = 1, b = 2;
Func<int, int, int> d = (x, y) => a*x+b*y;
}
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilation(source, options: options), symbolValidator: m =>
{
var displayClass = m.GlobalNamespace.GetMember<NamedTypeSymbol>("C.<>c__DisplayClass0_0");
AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute" }, GetAttributeNames(displayClass.GetAttributes()));
foreach (var member in displayClass.GetMembers())
{
Assert.Equal(0, member.GetAttributes().Length);
}
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void AnonymousTypes(OptimizationLevel optimizationLevel)
{
string source = @"
class C
{
void Goo()
{
var x = new { X = 1, Y = 2 };
}
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilation(source, options: options), symbolValidator: m =>
{
var anon = m.ContainingAssembly.GetTypeByMetadataName("<>f__AnonymousType0`2");
string[] expected;
if (options.OptimizationLevel == OptimizationLevel.Debug)
{
expected = new[] { "DebuggerDisplayAttribute", "CompilerGeneratedAttribute" };
}
else
{
expected = new[] { "CompilerGeneratedAttribute" };
}
AssertEx.SetEqual(expected, GetAttributeNames(anon.GetAttributes()));
foreach (var member in anon.GetMembers())
{
var actual = GetAttributeNames(member.GetAttributes());
switch (member.Name)
{
case "<X>i__Field":
case "<Y>i__Field":
expected = new[] { "DebuggerBrowsableAttribute" };
break;
case ".ctor":
case "Equals":
case "GetHashCode":
case "ToString":
expected = new[] { "DebuggerHiddenAttribute" };
break;
case "X":
case "get_X":
case "Y":
case "get_Y":
expected = new string[] { };
break;
default:
throw TestExceptionUtilities.UnexpectedValue(member.Name);
}
AssertEx.SetEqual(expected, actual);
}
});
}
[Fact]
public void AnonymousTypes_DebuggerDisplay()
{
string source = @"
public class C
{
public void Goo()
{
var _0 = new { };
var _1 = new { X0 = 1 };
var _2 = new { X0 = 1, X1 = 1 };
var _3 = new { X0 = 1, X1 = 1, X2 = 1 };
var _4 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1 };
var _5 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1, X4 = 1 };
var _6 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1, X4 = 1, X5 = 1 };
var _7 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1, X4 = 1, X5 = 1, X6 = 1 };
var _8 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1, X4 = 1, X5 = 1, X6 = 1, X7 = 1 };
var _10 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1, X4 = 1, X5 = 1, X6 = 1, X7 = 1, X8 = 1 };
var _11 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1, X4 = 1, X5 = 1, X6 = 1, X7 = 1, X8 = 1, X9 = 1 };
var _12 = new { X0 = 1, X1 = 1, X2 = 1, X3 = 1, X4 = 1, X5 = 1, X6 = 1, X7 = 1, X8 = 1, X9 = 1, X10 = 1 };
var _13 = new {
X10 = 1, X11 = 1, X12 = 1, X13 = 1, X14 = 1, X15 = 1, X16 = 1, X17 = 1,
X20 = 1, X21 = 1, X22 = 1, X23 = 1, X24 = 1, X25 = 1, X26 = 1, X27 = 1,
X30 = 1, X31 = 1, X32 = 1, X33 = 1, X34 = 1, X35 = 1, X36 = 1, X37 = 1,
X40 = 1, X41 = 1, X42 = 1, X43 = 1, X44 = 1, X45 = 1, X46 = 1, X47 = 1,
X50 = 1, X51 = 1, X52 = 1, X53 = 1, X54 = 1, X55 = 1, X56 = 1, X57 = 1,
X60 = 1, X61 = 1, X62 = 1, X63 = 1, X64 = 1, X65 = 1, X66 = 1, X67 = 1,
};
}
}
";
var comp = CreateCompilation(source, options: TestOptions.DebugDll);
CompileAndVerify(comp, symbolValidator: m =>
{
var assembly = m.ContainingAssembly;
Assert.Equal(@"\{ }", GetDebuggerDisplayString(assembly, 0, 0));
Assert.Equal(@"\{ X0 = {X0} }", GetDebuggerDisplayString(assembly, 1, 1));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1} }", GetDebuggerDisplayString(assembly, 2, 2));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2} }", GetDebuggerDisplayString(assembly, 3, 3));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3} }", GetDebuggerDisplayString(assembly, 4, 4));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3}, X4 = {X4} }", GetDebuggerDisplayString(assembly, 5, 5));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3}, X4 = {X4}, X5 = {X5} }", GetDebuggerDisplayString(assembly, 6, 6));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3}, X4 = {X4}, X5 = {X5}, X6 = {X6} }", GetDebuggerDisplayString(assembly, 7, 7));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3}, X4 = {X4}, X5 = {X5}, X6 = {X6}, X7 = {X7} }", GetDebuggerDisplayString(assembly, 8, 8));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3}, X4 = {X4}, X5 = {X5}, X6 = {X6}, X7 = {X7}, X8 = {X8} }", GetDebuggerDisplayString(assembly, 9, 9));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3}, X4 = {X4}, X5 = {X5}, X6 = {X6}, X7 = {X7}, X8 = {X8}, X9 = {X9} }", GetDebuggerDisplayString(assembly, 10, 10));
Assert.Equal(@"\{ X0 = {X0}, X1 = {X1}, X2 = {X2}, X3 = {X3}, X4 = {X4}, X5 = {X5}, X6 = {X6}, X7 = {X7}, X8 = {X8}, X9 = {X9} ... }", GetDebuggerDisplayString(assembly, 11, 11));
Assert.Equal(@"\{ X10 = {X10}, X11 = {X11}, X12 = {X12}, X13 = {X13}, X14 = {X14}, X15 = {X15}, X16 = {X16}, X17 = {X17}, X20 = {X20}, X21 = {X21} ... }",
GetDebuggerDisplayString(assembly, 12, 48));
});
string GetDebuggerDisplayString(AssemblySymbol assembly, int ordinal, int fieldCount)
{
NamedTypeSymbol anon;
if (fieldCount == 0)
{
anon = assembly.GetTypeByMetadataName("<>f__AnonymousType0");
}
else
{
anon = assembly.GetTypeByMetadataName("<>f__AnonymousType" + ordinal + "`" + fieldCount);
}
var dd = anon.GetAttributes().Where(a => a.AttributeClass.Name == "DebuggerDisplayAttribute").Single();
return (string)dd.ConstructorArguments.Single().Value;
}
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void Iterator(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Collections.Generic;
public class C
{
public IEnumerable<int> Iterator()
{
yield return 1;
}
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilation(source, options: options), symbolValidator: module =>
{
var iter = module.ContainingAssembly.GetTypeByMetadataName("C+<Iterator>d__0");
AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute" }, GetAttributeNames(iter.GetAttributes()));
foreach (var member in iter.GetMembers().Where(member => member is MethodSymbol))
{
switch (member.Name)
{
case ".ctor":
case "System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator":
case "System.Collections.IEnumerable.GetEnumerator":
case "System.Collections.IEnumerator.Reset":
case "System.IDisposable.Dispose":
case "System.Collections.Generic.IEnumerator<System.Int32>.get_Current":
case "System.Collections.IEnumerator.get_Current":
AssertEx.SetEqual(new[] { "DebuggerHiddenAttribute" }, GetAttributeNames(member.GetAttributes()));
break;
case "System.Collections.IEnumerator.Current":
case "System.Collections.Generic.IEnumerator<System.Int32>.Current":
case "MoveNext":
AssertEx.SetEqual(new string[] { }, GetAttributeNames(member.GetAttributes()));
break;
default:
throw TestExceptionUtilities.UnexpectedValue(member.Name);
}
}
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void Async(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Threading.Tasks;
class C
{
public async Task<int> Goo()
{
for (int x = 1; x < 10; x++)
{
await Goo();
}
return 1;
}
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var goo = module.GlobalNamespace.GetMember<MethodSymbol>("C.Goo");
AssertEx.SetEqual(options.OptimizationLevel == OptimizationLevel.Debug ?
new[] { "AsyncStateMachineAttribute", "DebuggerStepThroughAttribute" } :
new[] { "AsyncStateMachineAttribute" }, GetAttributeNames(goo.GetAttributes()));
var iter = module.GlobalNamespace.GetMember<NamedTypeSymbol>("C.<Goo>d__0");
AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute" }, GetAttributeNames(iter.GetAttributes()));
foreach (var member in iter.GetMembers().Where(s => s.Kind == SymbolKind.Method))
{
switch (member.Name)
{
case ".ctor":
break;
case "SetStateMachine":
AssertEx.SetEqual(new[] { "DebuggerHiddenAttribute" }, GetAttributeNames(member.GetAttributes()));
break;
case "MoveNext":
AssertEx.SetEqual(new string[] { }, GetAttributeNames(member.GetAttributes()));
break;
default:
throw TestExceptionUtilities.UnexpectedValue(member.Name);
}
}
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
[WorkItem(431, "https://github.com/dotnet/roslyn/issues/431")]
public void BaseMethodWrapper(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Threading.Tasks;
class A
{
public virtual async Task<int> GetIntAsync()
{
return 42;
}
}
class B : A
{
public override async Task<int> GetIntAsync()
{
return await base.GetIntAsync();
}
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var attributes = module.GlobalNamespace.GetTypeMember("B").GetMember<MethodSymbol>("<>n__0").GetAttributes();
AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute", "DebuggerHiddenAttribute" }, GetAttributeNames(attributes));
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
[WorkItem(38801, "https://github.com/dotnet/roslyn/issues/38801")]
public void BaseMethodWrapper_DoNotInheritAttributes(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Threading.Tasks;
class Attr : System.Attribute { }
class A
{
[Attr]
[return: Attr]
public virtual async Task<int> GetIntAsync([Attr] int x)
{
return 42;
}
}
class B : A
{
public override async Task<int> GetIntAsync(int x)
{
return await base.GetIntAsync(x);
}
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var baseMethodWrapper = module.GlobalNamespace.GetTypeMember("B").GetMember<MethodSymbol>("<>n__0");
AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute", "DebuggerHiddenAttribute" }, GetAttributeNames(baseMethodWrapper.GetAttributes()));
Assert.Empty(baseMethodWrapper.GetReturnTypeAttributes());
var parameter = baseMethodWrapper.Parameters.Single();
Assert.Empty(parameter.GetAttributes());
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
[WorkItem(38801, "https://github.com/dotnet/roslyn/issues/38801")]
public void BaseMethodWrapper_DoNotInheritAttributes_TypeParameter(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Threading.Tasks;
class Attr : System.Attribute { }
class A
{
[Attr]
[return: Attr]
public virtual async Task<T> GetAsync<[Attr] T>([Attr] T t)
{
return t;
}
}
class B : A
{
[Attr]
[return: Attr]
public override async Task<T> GetAsync<[Attr] T>([Attr] T t)
{
return await base.GetAsync(t);
}
}
";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var baseMethodWrapper = module.GlobalNamespace.GetTypeMember("B").GetMember<MethodSymbol>("<>n__0");
AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute", "DebuggerHiddenAttribute" }, GetAttributeNames(baseMethodWrapper.GetAttributes()));
Assert.Empty(baseMethodWrapper.GetReturnTypeAttributes());
var parameter = baseMethodWrapper.Parameters.Single();
Assert.Empty(parameter.GetAttributes());
var typeParameter = baseMethodWrapper.TypeParameters.Single();
Assert.Empty(typeParameter.GetAttributes());
});
}
[Fact]
public void SubstitutedTypeParameter_Attributes()
{
string source = @"
class Attr : System.Attribute { }
internal class C1<T1>
{
internal class C2<[Attr] T2> { }
}
";
var comp = CreateCompilation(source);
var c1OfInt = comp.GetTypeByMetadataName("C1`1").Construct(comp.GetSpecialType(SpecialType.System_Int32));
var c2 = c1OfInt.GetTypeMember("C2");
var typeParam = c2.TypeParameters.Single();
Assert.Equal(new[] { "Attr" }, GetAttributeNames(typeParam.GetAttributes()));
}
[Fact]
[WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")]
public void RecordSynthesizedMembers()
{
string source = @"
record R
{
public int MyProperty { get; }
}
";
CompileAndVerify(source, symbolValidator: validate, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All));
static void validate(ModuleSymbol module)
{
var record = module.GlobalNamespace.GetTypeMember("R");
Assert.Equal(15, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute.
var equalityContractGetter = record.GetMember("get_EqualityContract");
validateCompilerGeneratedAttribute(equalityContractGetter);
var toString = record.GetMember(WellKnownMemberNames.ObjectToString);
validateCompilerGeneratedAttribute(toString);
var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName);
validateCompilerGeneratedAttribute(printMembers);
var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName);
validateCompilerGeneratedAttribute(op_Equality);
var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName);
validateCompilerGeneratedAttribute(op_Inequality);
var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode);
validateCompilerGeneratedAttribute(getHashCode);
var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals);
Assert.Equal(2, equals.Length);
validateCompilerGeneratedAttribute(equals[0]);
validateCompilerGeneratedAttribute(equals[1]);
var clone = record.GetMember(WellKnownMemberNames.CloneMethodName);
validateCompilerGeneratedAttribute(clone);
var ctor = record.GetMembers(WellKnownMemberNames.InstanceConstructorName);
Assert.Equal(2, ctor.Length);
Assert.Equal("R..ctor(R original)", ctor[0].ToTestDisplayString());
validateCompilerGeneratedAttribute(ctor[0]);
Assert.Equal("R..ctor()", ctor[1].ToTestDisplayString()); // parameterless constructor
Assert.Empty(ctor[1].GetAttributes()); // shouldn't have attribute.
var equalityContract = record.GetMember("EqualityContract");
validateCompilerGeneratedAttribute(equalityContract);
var myProperty = record.GetMember("MyProperty");
Assert.Empty(myProperty.GetAttributes());
var myPropertyGetter = record.GetMember("get_MyProperty");
validateCompilerGeneratedAttribute(myPropertyGetter);
var myPropertyBackingField = record.GetMember("<MyProperty>k__BackingField");
validateCompilerGeneratedAttribute(myPropertyBackingField);
}
static void validateCompilerGeneratedAttribute(Symbol symbol)
{
var attributeNames = GetAttributeNames(symbol.GetAttributes());
Assert.Contains("CompilerGeneratedAttribute", attributeNames);
}
}
[Fact]
[WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")]
public void RecordStructSynthesizedMembers()
{
string source = @"
record struct R
{
public int MyProperty { get; }
}
";
CompileAndVerify(source, symbolValidator: validate, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All));
static void validate(ModuleSymbol module)
{
var record = module.GlobalNamespace.GetTypeMember("R");
Assert.Equal(11, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute.
var toString = record.GetMember(WellKnownMemberNames.ObjectToString);
validateCompilerGeneratedAttribute(toString);
var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName);
validateCompilerGeneratedAttribute(printMembers);
var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName);
validateCompilerGeneratedAttribute(op_Equality);
var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName);
validateCompilerGeneratedAttribute(op_Inequality);
var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode);
validateCompilerGeneratedAttribute(getHashCode);
var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals);
Assert.Equal(2, equals.Length);
validateCompilerGeneratedAttribute(equals[0]);
validateCompilerGeneratedAttribute(equals[1]);
var ctor = record.GetMember(WellKnownMemberNames.InstanceConstructorName);
Assert.Empty(ctor.GetAttributes());
var myProperty = record.GetMember("MyProperty");
Assert.Empty(myProperty.GetAttributes());
var myPropertyGetter = record.GetMember("get_MyProperty");
validateCompilerGeneratedAttribute(myPropertyGetter);
var myPropertyBackingField = record.GetMember("<MyProperty>k__BackingField");
validateCompilerGeneratedAttribute(myPropertyBackingField);
}
static void validateCompilerGeneratedAttribute(Symbol symbol)
{
var attributeNames = GetAttributeNames(symbol.GetAttributes());
Assert.Contains("CompilerGeneratedAttribute", attributeNames);
}
}
[Fact]
[WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")]
public void RecordSynthesizedMembers_2()
{
string source = @"
record R(int P1);
namespace System.Runtime.CompilerServices
{
public static class IsExternalInit { }
}
";
// [ : R::set_P1] Cannot change initonly field outside its .ctor.
CompileAndVerify(source,
symbolValidator: validate,
options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All),
verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails);
static void validate(ModuleSymbol module)
{
var record = module.GlobalNamespace.GetTypeMember("R");
Assert.Equal(17, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute.
var p1_backingField = record.GetMember("<P1>k__BackingField");
validateCompilerGeneratedAttribute(p1_backingField);
var equalityContractGetter = record.GetMember("get_EqualityContract");
validateCompilerGeneratedAttribute(equalityContractGetter);
var get_P1 = record.GetMember("get_P1");
validateCompilerGeneratedAttribute(get_P1);
var set_P1 = record.GetMember("set_P1");
validateCompilerGeneratedAttribute(set_P1);
var toString = record.GetMember(WellKnownMemberNames.ObjectToString);
validateCompilerGeneratedAttribute(toString);
var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName);
validateCompilerGeneratedAttribute(printMembers);
var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName);
validateCompilerGeneratedAttribute(op_Equality);
var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName);
validateCompilerGeneratedAttribute(op_Inequality);
var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode);
validateCompilerGeneratedAttribute(getHashCode);
var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals);
Assert.Equal(2, equals.Length);
validateCompilerGeneratedAttribute(equals[0]);
validateCompilerGeneratedAttribute(equals[1]);
var clone = record.GetMember(WellKnownMemberNames.CloneMethodName);
validateCompilerGeneratedAttribute(clone);
var ctor = record.GetMembers(WellKnownMemberNames.InstanceConstructorName);
Assert.Equal(2, ctor.Length);
Assert.Equal("R..ctor(System.Int32 P1)", ctor[0].ToTestDisplayString());
Assert.Equal("R..ctor(R original)", ctor[1].ToTestDisplayString());
validateCompilerGeneratedAttribute(ctor[1]);
Assert.Empty(ctor[0].GetAttributes());
var deconstruct = record.GetMember(WellKnownMemberNames.DeconstructMethodName);
validateCompilerGeneratedAttribute(deconstruct);
var equalityContract = record.GetMember("EqualityContract");
validateCompilerGeneratedAttribute(equalityContract);
var p1 = record.GetMember("P1");
Assert.Empty(p1.GetAttributes());
}
static void validateCompilerGeneratedAttribute(Symbol symbol)
{
var attributeNames = GetAttributeNames(symbol.GetAttributes());
Assert.Contains("CompilerGeneratedAttribute", attributeNames);
}
}
[Fact]
[WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")]
public void RecordStructSynthesizedMembers_2()
{
string source = @"
record struct R(int P1);
";
CompileAndVerify(source, symbolValidator: validate, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All));
void validate(ModuleSymbol module)
{
var record = module.GlobalNamespace.GetTypeMember("R");
Assert.Equal(14, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute.
var p1_backingField = record.GetMember("<P1>k__BackingField");
validateCompilerGeneratedAttribute(p1_backingField);
var ctor = record.GetMembers(WellKnownMemberNames.InstanceConstructorName);
Assert.Equal(2, ctor.Length);
Assert.Equal("R..ctor()", ctor[0].ToTestDisplayString());
Assert.Equal("R..ctor(System.Int32 P1)", ctor[1].ToTestDisplayString());
Assert.Empty(ctor[0].GetAttributes());
Assert.Empty(ctor[1].GetAttributes());
var get_P1 = record.GetMember("get_P1");
validateCompilerGeneratedAttribute(get_P1);
var set_P1 = record.GetMember("set_P1");
validateCompilerGeneratedAttribute(set_P1);
var toString = record.GetMember(WellKnownMemberNames.ObjectToString);
validateCompilerGeneratedAttribute(toString);
var printMembers = record.GetMember(WellKnownMemberNames.PrintMembersMethodName);
validateCompilerGeneratedAttribute(printMembers);
var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName);
validateCompilerGeneratedAttribute(op_Equality);
var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName);
validateCompilerGeneratedAttribute(op_Inequality);
var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode);
validateCompilerGeneratedAttribute(getHashCode);
var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals);
Assert.Equal(2, equals.Length);
validateCompilerGeneratedAttribute(equals[0]);
validateCompilerGeneratedAttribute(equals[1]);
var deconstruct = record.GetMember(WellKnownMemberNames.DeconstructMethodName);
validateCompilerGeneratedAttribute(deconstruct);
var p1 = record.GetMember("P1");
Assert.Empty(p1.GetAttributes());
}
void validateCompilerGeneratedAttribute(Symbol symbol)
{
var attributeNames = GetAttributeNames(symbol.GetAttributes());
Assert.Contains("CompilerGeneratedAttribute", attributeNames);
}
}
[Fact]
[WorkItem(46439, "https://github.com/dotnet/roslyn/issues/46439")]
public void AttributeIsMissing()
{
string source = @"
record struct R;
";
var comp = CreateCompilation(source);
comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_CompilerGeneratedAttribute);
var verifier = CompileAndVerify(comp, symbolValidator: validate);
verifier.VerifyDiagnostics();
void validate(ModuleSymbol module)
{
var record = module.GlobalNamespace.GetTypeMember("R");
Assert.Equal(7, record.GetMembers().Length); // If a new record member is added, extend the test with its behavior regarding CompilerGeneratedAttribute.
var ctor = record.GetMember(WellKnownMemberNames.InstanceConstructorName);
Assert.Empty(ctor.GetAttributes());
var toString = record.GetMember(WellKnownMemberNames.ObjectToString);
Assert.Empty(toString.GetAttributes());
var op_Equality = record.GetMember(WellKnownMemberNames.EqualityOperatorName);
Assert.Empty(op_Equality.GetAttributes());
var op_Inequality = record.GetMember(WellKnownMemberNames.InequalityOperatorName);
Assert.Empty(op_Inequality.GetAttributes());
var getHashCode = record.GetMember(WellKnownMemberNames.ObjectGetHashCode);
Assert.Empty(getHashCode.GetAttributes());
var equals = record.GetMembers(WellKnownMemberNames.ObjectEquals);
Assert.Equal(2, equals.Length);
Assert.Empty(equals[0].GetAttributes());
Assert.Empty(equals[1].GetAttributes());
}
}
#endregion
#region CompilationRelaxationsAttribute, RuntimeCompatibilityAttribute, DebuggableAttribute
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void SynthesizedAllAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[1], isSynthesized: true);
VerifyDebuggableAttribute(attributes[2], options.OptimizationLevel, isSynthesized: true);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void AppliedCompilationRelaxations(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
using System.Runtime.CompilerServices;
[assembly: CompilationRelaxationsAttribute(0)]
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyRuntimeCompatibilityAttribute(attributes[0], isSynthesized: true);
VerifyDebuggableAttribute(attributes[1], options.OptimizationLevel, isSynthesized: true);
VerifyCompilationRelaxationsAttribute(attributes[2], isSynthesized: false);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void AppliedRuntimeCompatibility(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
using System.Runtime.CompilerServices;
[assembly: RuntimeCompatibilityAttribute()]
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyDebuggableAttribute(attributes[1], options.OptimizationLevel, isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[2], isSynthesized: false);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void AppliedDebuggable(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
using System.Diagnostics;
[assembly: DebuggableAttribute(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[1], isSynthesized: true);
VerifyDebuggableAttribute(attributes[2], options.OptimizationLevel, isSynthesized: false);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void AppliedDebuggableOnBothAssemblyAndModule(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
using System.Diagnostics;
[module: DebuggableAttribute(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: DebuggableAttribute(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
public class Test
{
public static void Main()
{
}
}";
var parseOptions = TestOptions.Regular.WithNoRefSafetyRulesAttribute();
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, parseOptions: parseOptions, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
VerifyDebuggableAttribute(module.GetAttributes().Single(), optimizationLevel, isSynthesized: false);
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[1], isSynthesized: true);
VerifyDebuggableAttribute(attributes[2], options.OptimizationLevel, isSynthesized: false);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void AppliedCompilationRelaxationsAndRuntimeCompatibility(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
using System.Runtime.CompilerServices;
[assembly: CompilationRelaxationsAttribute(0)]
[assembly: RuntimeCompatibilityAttribute()]
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyDebuggableAttribute(attributes[0], options.OptimizationLevel, isSynthesized: true);
VerifyCompilationRelaxationsAttribute(attributes[1], isSynthesized: false);
VerifyRuntimeCompatibilityAttribute(attributes[2], isSynthesized: false);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void ModuleCompilationRelaxationsDoNotSuppressAssemblyAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
using System.Runtime.CompilerServices;
[module: CompilationRelaxationsAttribute(0)]
public class Test
{
public static void Main()
{
}
}";
var parseOptions = TestOptions.Regular.WithNoRefSafetyRulesAttribute();
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, parseOptions: parseOptions, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
VerifyCompilationRelaxationsAttribute(module.GetAttributes().Single(), isSynthesized: false);
var assemblyAttributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, assemblyAttributes.Length);
}
else
{
Assert.Equal(3, assemblyAttributes.Length);
VerifyCompilationRelaxationsAttribute(assemblyAttributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(assemblyAttributes[1], isSynthesized: true);
VerifyDebuggableAttribute(assemblyAttributes[2], options.OptimizationLevel, isSynthesized: true);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void ModuleDebuggableDoNotSuppressAssemblyAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
using System.Diagnostics;
[module: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
public class Test
{
public static void Main()
{
}
}";
var parseOptions = TestOptions.Regular.WithNoRefSafetyRulesAttribute();
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, parseOptions: parseOptions, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
VerifyDebuggableAttribute(module.GetAttributes().Single(), options.OptimizationLevel, isSynthesized: false);
var assemblyAttributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, assemblyAttributes.Length);
}
else
{
Assert.Equal(3, assemblyAttributes.Length);
VerifyCompilationRelaxationsAttribute(assemblyAttributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(assemblyAttributes[1], isSynthesized: true);
VerifyDebuggableAttribute(assemblyAttributes[2], options.OptimizationLevel, isSynthesized: true);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void MissingWellKnownAttributesNoDiagnosticsAndNoSynthesizedAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
var compilation = CreateEmptyCompilation("", parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: options);
if (outputKind.IsApplication())
{
compilation.VerifyDiagnostics(
// error CS5001: Program does not contain a static 'Main' method suitable for an entry point
Diagnostic(ErrorCode.ERR_NoEntryPoint));
}
else
{
// ILVerify: Failed to load type 'System.String' from assembly
// ILVerify: The format of a DLL or executable being loaded is invalid
var verify = outputKind.IsNetModule()
? Verification.Fails
: Verification.FailsILVerify;
CompileAndVerify(compilation, verify: verify, symbolValidator: module =>
{
var assemblyAttributes = module.ContainingAssembly.GetAttributes();
Assert.Equal(0, assemblyAttributes.Length);
});
}
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void MissingWellKnownAttributeEnumsNoDiagnosticsAndNoSynthesizedAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var code = @"
namespace System.Diagnostics
{
public sealed class DebuggableAttribute: Attribute
{
public DebuggableAttribute(bool isJITTrackingEnabled, bool isJITOptimizerDisabled) {}
}
}
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
var compilation = CreateCompilation(code, options: options);
CompileAndVerify(compilation, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(2, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[1], isSynthesized: true);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void InaccessibleWellKnownAttributeEnumsNoDiagnosticsAndNoSynthesizedAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var code = @"
namespace System.Diagnostics
{
public sealed class DebuggableAttribute: Attribute
{
public DebuggableAttribute(bool isJITTrackingEnabled, bool isJITOptimizerDisabled) {}
private enum DebuggingModes
{
None = 0,
Default = 1,
IgnoreSymbolStoreSequencePoints = 2,
EnableEditAndContinue = 4,
DisableOptimizations = 256,
}
}
}
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
var compilation = CreateCompilation(code, options: options);
CompileAndVerify(compilation, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(2, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[1], isSynthesized: true);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void WellKnownAttributeMissingCtorNoDiagnosticsAndNoSynthesizedAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var code = @"
namespace System.Diagnostics
{
public sealed class DebuggableAttribute: Attribute
{
public enum DebuggingModes
{
None = 0,
Default = 1,
IgnoreSymbolStoreSequencePoints = 2,
EnableEditAndContinue = 4,
DisableOptimizations = 256,
}
}
}
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
var compilation = CreateCompilation(code, options: options);
CompileAndVerify(compilation, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(2, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[1], isSynthesized: true);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void WellKnownAttributeInvalidTypeNoDiagnosticsAndNoSynthesizedAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var code = @"
namespace System.Diagnostics
{
public sealed class DebuggableAttribute: Attribute
{
public DebuggableAttribute(bool isJITTrackingEnabled, bool isJITOptimizerDisabled) {}
public struct DebuggingModes
{
}
}
}
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
var compilation = CreateCompilation(code, options: options);
CompileAndVerify(compilation, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(2, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[1], isSynthesized: true);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void MissingWellKnownAttributeMembersProduceDiagnostics(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var source = @"
namespace System.Runtime.CompilerServices
{
sealed public class CompilationRelaxationsAttribute : System.Attribute
{
}
sealed public class RuntimeCompatibilityAttribute : System.Attribute
{
public RuntimeCompatibilityAttribute(int dummy) {}
}
}
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
var compilation = CreateCompilation(source, options: options);
if (outputKind.IsNetModule())
{
CompileAndVerify(compilation, verify: Verification.Skipped, symbolValidator: module =>
{
var assemblyAttributes = module.ContainingAssembly.GetAttributes();
Assert.Equal(0, assemblyAttributes.Length);
});
}
else
{
compilation.VerifyDiagnostics(
// error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.CompilationRelaxationsAttribute..ctor'
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Runtime.CompilerServices.CompilationRelaxationsAttribute", ".ctor"),
// error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RuntimeCompatibilityAttribute..ctor'
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Runtime.CompilerServices.RuntimeCompatibilityAttribute", ".ctor"),
// error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RuntimeCompatibilityAttribute.WrapNonExceptionThrows'
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Runtime.CompilerServices.RuntimeCompatibilityAttribute", "WrapNonExceptionThrows"));
}
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void AppliedCompilationRelaxationsOnModuleSuppressesAssemblyAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var referenceComp = CreateCompilation(@"
using System.Runtime.CompilerServices;
[assembly: CompilationRelaxationsAttribute(0)]
", options: TestOptions.CreateTestOptions(OutputKind.NetModule, optimizationLevel));
var reference = ModuleMetadata.CreateFromImage(referenceComp.EmitToArray()).GetReference();
var source = @"
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, references: new[] { reference }, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyRuntimeCompatibilityAttribute(attributes[0], isSynthesized: true);
VerifyDebuggableAttribute(attributes[1], options.OptimizationLevel, isSynthesized: true);
VerifyCompilationRelaxationsAttribute(attributes[2], isSynthesized: false);
}
});
}
[Theory]
[MemberData(nameof(FullMatrixTheoryData))]
public void AppliedRuntimeCompatibilityOnModuleSuppressesAssemblyAttributes(OutputKind outputKind, OptimizationLevel optimizationLevel)
{
var referenceComp = CreateCompilation(@"
using System.Runtime.CompilerServices;
[assembly: RuntimeCompatibilityAttribute()]
", options: TestOptions.CreateTestOptions(OutputKind.NetModule, optimizationLevel));
var reference = ModuleMetadata.CreateFromImage(referenceComp.EmitToArray()).GetReference();
var source = @"
public class Test
{
public static void Main()
{
}
}";
var options = TestOptions.CreateTestOptions(outputKind, optimizationLevel);
CompileAndVerify(source, references: new[] { reference }, options: options, verify: outputKind.IsNetModule() ? Verification.Skipped : Verification.Passes, symbolValidator: module =>
{
var attributes = module.ContainingAssembly.GetAttributes();
if (outputKind.IsNetModule())
{
Assert.Equal(0, attributes.Length);
}
else
{
Assert.Equal(3, attributes.Length);
VerifyCompilationRelaxationsAttribute(attributes[0], isSynthesized: true);
VerifyDebuggableAttribute(attributes[1], options.OptimizationLevel, isSynthesized: true);
VerifyRuntimeCompatibilityAttribute(attributes[2], isSynthesized: false);
}
});
}
#endregion
#region UnverifiableCode, SecurityPermission
[Theory]
[InlineData(OutputKind.DynamicallyLinkedLibrary)]
[InlineData(OutputKind.NetModule)]
public void CheckUnsafeAttributes(OutputKind outputKind)
{
string source = @"
unsafe class C
{
public static void Main()
{
}
}";
var compilation = CreateCompilationWithMscorlib40(source, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.CreateTestOptions(outputKind, OptimizationLevel.Release, allowUnsafe: true));
//Skipped because PeVerify fails to run with "The module was expected to contain an assembly manifest."
CompileAndVerify(compilation, verify: Verification.Skipped, symbolValidator: module =>
{
var unverifiableCode = module.GetAttributes().Single();
Assert.Equal("System.Security.UnverifiableCodeAttribute", unverifiableCode.AttributeClass.ToTestDisplayString());
Assert.Empty(unverifiableCode.AttributeConstructor.Parameters);
Assert.Empty(unverifiableCode.CommonConstructorArguments);
Assert.Empty(unverifiableCode.CommonNamedArguments);
if (outputKind.IsNetModule())
{
// Modules security attributes are copied to assemblies they're included in
var moduleReference = ModuleMetadata.CreateFromImage(compilation.EmitToArray()).GetReference();
CompileAndVerifyWithMscorlib40("", references: new[] { moduleReference }, symbolValidator: validateSecurity, verify: Verification.Skipped);
}
else
{
validateSecurity(module);
}
});
void validateSecurity(ModuleSymbol module)
{
ValidateDeclSecurity(module, new DeclSecurityEntry
{
ActionFlags = DeclarativeSecurityAction.RequestMinimum,
ParentKind = SymbolKind.Assembly,
PermissionSet =
"." + // always start with a dot
"\u0001" + // number of attributes (small enough to fit in 1 byte)
"\u0080\u0084" + // length of UTF-8 string (0x80 indicates a 2-byte encoding)
"System.Security.Permissions.SecurityPermissionAttribute, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" + // attr type name
"\u0015" + // number of bytes in the encoding of the named arguments
"\u0001" + // number of named arguments
"\u0054" + // property (vs field)
"\u0002" + // type bool
"\u0010" + // length of UTF-8 string (small enough to fit in 1 byte)
"SkipVerification" + // property name
"\u0001", // argument value (true)
});
}
}
#endregion
#region AsyncStateMachineAttribute
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void AsyncStateMachineAttribute_Method(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Threading.Tasks;
class Test
{
public static async void F()
{
await Task.Delay(0);
}
}";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
var stateMachine = type.GetTypeMember("<F>d__0");
var asyncMethod = type.GetMember<MethodSymbol>("F");
var attributes = asyncMethod.GetAttributes();
var stateMachineAttribute = attributes.First();
Assert.Equal("AsyncStateMachineAttribute", stateMachineAttribute.AttributeClass.Name);
Assert.Equal(stateMachine, stateMachineAttribute.ConstructorArguments.Single().ValueInternal);
if (optimizationLevel == OptimizationLevel.Debug)
{
Assert.Equal(2, attributes.Length);
Assert.Equal("DebuggerStepThroughAttribute", attributes.Last().AttributeClass.Name);
}
else
{
Assert.Equal(1, attributes.Length);
}
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void AsyncStateMachineAttribute_Lambda(OptimizationLevel optimizationLevel)
{
string source = @"
using System;
using System.Threading.Tasks;
class Test
{
public static void F()
{
Action f = async () => { await Task.Delay(0); };
}
}";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("Test").GetTypeMember("<>c");
var stateMachine = type.GetTypeMember("<<F>b__0_0>d");
var asyncMethod = type.GetMember<MethodSymbol>("<F>b__0_0");
var attributes = asyncMethod.GetAttributes();
var stateMachineAttribute = attributes.First();
Assert.Equal("AsyncStateMachineAttribute", stateMachineAttribute.AttributeClass.Name);
Assert.Equal(stateMachine, stateMachineAttribute.ConstructorArguments.Single().ValueInternal);
if (optimizationLevel == OptimizationLevel.Debug)
{
Assert.Equal(2, attributes.Length);
Assert.Equal("DebuggerStepThroughAttribute", attributes.Last().AttributeClass.Name);
}
else
{
Assert.Equal(1, attributes.Length);
}
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void AsyncStateMachineAttribute_GenericStateMachineClass(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Threading.Tasks;
public class Test<T>
{
public async void F<U>(U u) where U : Test<int>, new()
{
await Task.Delay(0);
}
}";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
var stateMachine = type.GetTypeMember("<F>d__0");
var asyncMethod = type.GetMember<MethodSymbol>("F");
var attributes = asyncMethod.GetAttributes();
var stateMachineAttribute = attributes.First();
Assert.Equal("AsyncStateMachineAttribute", stateMachineAttribute.AttributeClass.Name);
Assert.Equal(stateMachine.AsUnboundGenericType(), stateMachineAttribute.ConstructorArguments.Single().ValueInternal);
if (optimizationLevel == OptimizationLevel.Debug)
{
Assert.Equal(2, attributes.Length);
Assert.Equal("DebuggerStepThroughAttribute", attributes.Last().AttributeClass.Name);
}
else
{
Assert.Equal(1, attributes.Length);
}
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void AsyncStateMachineAttribute_MetadataOnly(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Threading.Tasks;
class Test
{
public static async void F()
{
await Task.Delay(0);
}
}";
var referenceOptions = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
var reference = CreateCompilationWithMscorlib461(source, options: referenceOptions).EmitToImageReference(options: new EmitOptions(metadataOnly: true));
var options = TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All);
var compilation = CreateCompilationWithMscorlib461("", new[] { reference }, options: options);
var type = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
Assert.Equal(new[] { "F", ".ctor" }, type.GetMembers().SelectAsArray(m => m.Name));
var asyncMethod = type.GetMember<MethodSymbol>("F");
if (optimizationLevel == OptimizationLevel.Debug)
{
Assert.Equal("DebuggerStepThroughAttribute", asyncMethod.GetAttributes().Single().AttributeClass.Name);
}
else
{
Assert.Empty(asyncMethod.GetAttributes());
}
}
#endregion
#region IteratorStateMachineAttribute
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void IteratorStateMachineAttribute_Method(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Collections.Generic;
class Test
{
public static IEnumerable<int> F()
{
yield return 1;
}
}";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
var stateMachine = type.GetTypeMember("<F>d__0");
var iteratorMethod = type.GetMember<MethodSymbol>("F");
var iteratorAttribute = iteratorMethod.GetAttributes().Single();
Assert.Equal("IteratorStateMachineAttribute", iteratorAttribute.AttributeClass.Name);
Assert.Equal(stateMachine, iteratorAttribute.ConstructorArguments.Single().ValueInternal);
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void IteratorStateMachineAttribute_GenericStateMachineClass(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Collections.Generic;
public class Test<T>
{
public IEnumerable<int> F<U>(U u) where U : Test<int>, new()
{
yield return 1;
}
}";
var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module =>
{
var type = module.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
var stateMachine = type.GetTypeMember("<F>d__0");
var iteratorMethod = type.GetMember<MethodSymbol>("F");
var iteratorAttribute = iteratorMethod.GetAttributes().Single();
Assert.Equal("IteratorStateMachineAttribute", iteratorAttribute.AttributeClass.Name);
Assert.Equal(stateMachine.AsUnboundGenericType(), iteratorAttribute.ConstructorArguments.Single().ValueInternal);
});
}
[Theory]
[MemberData(nameof(OptimizationLevelTheoryData))]
public void IteratorStateMachineAttribute_MetadataOnly(OptimizationLevel optimizationLevel)
{
string source = @"
using System.Collections.Generic;
public class Test<T>
{
public IEnumerable<int> F<U>(U u) where U : Test<int>, new()
{
yield return 1;
}
}";
var referenceOptions = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel)
.WithMetadataImportOptions(MetadataImportOptions.All);
var reference = CreateCompilationWithMscorlib461(source, options: referenceOptions).EmitToImageReference(options: new EmitOptions(metadataOnly: true));
var options = TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All);
var compilation = CreateCompilationWithMscorlib461("", new[] { reference }, options: options);
var type = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Test");
Assert.Equal(new[] { "F", ".ctor" }, type.GetMembers().SelectAsArray(m => m.Name));
Assert.Empty(type.GetMember<MethodSymbol>("F").GetAttributes());
}
#endregion
[Fact, WorkItem(7809, "https://github.com/dotnet/roslyn/issues/7809")]
public void SynthesizeAttributeWithUseSiteErrorFails()
{
var parseOptions = TestOptions.Regular.WithNoRefSafetyRulesAttribute();
#region "mslib"
var mslibNoString = @"
namespace System
{
public class Object { }
public struct Int32 { }
public class ValueType { }
public class Attribute { }
public struct Void { }
}";
var mslib = mslibNoString + @"
namespace System
{
public class String { }
}";
#endregion
// Build an mscorlib including String
var mslibComp = CreateEmptyCompilation(new string[] { mslib }, parseOptions: parseOptions).VerifyDiagnostics();
var mslibRef = mslibComp.EmitToImageReference();
// Build an mscorlib without String
var mslibNoStringComp = CreateEmptyCompilation(new string[] { mslibNoString }, parseOptions: parseOptions).VerifyDiagnostics();
var mslibNoStringRef = mslibNoStringComp.EmitToImageReference();
var diagLibSource = @"
namespace System.Diagnostics
{
public class DebuggerDisplayAttribute : System.Attribute
{
public DebuggerDisplayAttribute(System.String s) { }
public System.String Type { get { return null; } set { } }
}
}
namespace System.Runtime.CompilerServices
{
public class CompilerGeneratedAttribute { }
}";
// Build Diagnostics referencing mscorlib with String
var diagLibComp = CreateEmptyCompilation(new string[] { diagLibSource }, parseOptions: parseOptions, references: new[] { mslibRef }).VerifyDiagnostics();
var diagLibRef = diagLibComp.EmitToImageReference();
// Create compilation using Diagnostics but referencing mscorlib without String
var comp = CreateEmptyCompilation(new SyntaxTree[] { Parse("", options: parseOptions) }, references: new[] { diagLibRef, mslibNoStringRef });
// Attribute cannot be synthesized because ctor has a use-site error (String type missing)
var attribute = comp.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__ctor);
Assert.Null(attribute);
// Attribute cannot be synthesized because type in named argument has use-site error (String type missing)
var attribute2 = comp.TrySynthesizeAttribute(
WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor,
namedArguments: ImmutableArray.Create(new KeyValuePair<WellKnownMember, TypedConstant>(
WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__Type,
new TypedConstant(comp.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, "unused"))));
Assert.Null(attribute2);
}
}
}
|