/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_NullablePublicOnly.cs
625 строк
25 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.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class AttributeTests_NullablePublicOnly : CSharpTestBase { [Fact] public void ExplicitAttribute_FromSource() { var source = @"public class A<T> { } public class B : A<object?> { }"; var options = WithNullableEnable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; CSharpTestSource sources = new[] { NullablePublicOnlyAttributeDefinition, source }; var comp = CreateCompilation(sources, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, publicDefinition: true)); comp = CreateCompilation(sources, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, publicDefinition: true)); } [Fact] public void ExplicitAttribute_FromMetadata() { var source = @"public class A<T> { } public class B : A<object?> { }"; var comp = CreateCompilation(NullablePublicOnlyAttributeDefinition, parseOptions: TestOptions.Regular7); comp.VerifyDiagnostics(); var ref1 = comp.EmitToImageReference(); var options = WithNullableEnable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; comp = CreateCompilation(source, references: new[] { ref1 }, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: false, includesAttributeUse: false, publicDefinition: true)); comp = CreateCompilation(source, references: new[] { ref1 }, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: false, includesAttributeUse: true, publicDefinition: true)); } [Fact] public void ExplicitAttribute_MissingSingleValueConstructor() { var source1 = @"namespace System.Runtime.CompilerServices { public sealed class NullablePublicOnlyAttribute : Attribute { } }"; var source2 = @"public class A<T> { } public class B : A<object?> { }"; var options = WithNullableEnable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; var comp = CreateCompilation(new[] { source1, source2 }, options: options, parseOptions: parseOptions); comp.VerifyEmitDiagnostics(); comp = CreateCompilation(new[] { source1, source2 }, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); comp.VerifyEmitDiagnostics( // error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.NullablePublicOnlyAttribute..ctor' Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Runtime.CompilerServices.NullablePublicOnlyAttribute", ".ctor").WithLocation(1, 1)); } [Fact] public void EmptyProject() { var source = @""; var options = WithNullableEnable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; var comp = CreateCompilation(source, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(source, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void CSharp7_NoAttribute() { var source = @"public class A<T> { } public class B : A<object> { }"; var options = TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular7; var comp = CreateCompilation(source, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(source, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void NullableEnabled() { var source = @"public class A<T> { } public class B : A<object?> { }"; var options = WithNullableEnable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; var comp = CreateCompilation(source, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(source, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNullablePublicOnlyAttribute); } [Fact] public void NullableEnabled_NoPublicMembers() { var source = @"class A<T> { } class B : A<object?> { }"; var options = WithNullableEnable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; var comp = CreateCompilation(source, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(source, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void NullableDisabled() { var source = @"public class A<T> { } public class B : A<object> { }"; var options = WithNullableDisable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; var comp = CreateCompilation(source, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(source, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void NullableDisabled_Annotation() { var source = @"public class A<T> { } public class B : A<object?> { }"; var options = WithNullableDisable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; var comp = CreateCompilation(source, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(source, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNullablePublicOnlyAttribute); } [Fact] public void NullableDisabled_OtherNullableAttributeDefinitions() { var source = @"public class Program { }"; var options = WithNullableDisable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; CSharpTestSource sources = new[] { NullableAttributeDefinition, NullableContextAttributeDefinition, source }; var comp = CreateCompilation(sources, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(sources, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void NullableEnabled_MethodBodyOnly() { var source0 = @"#nullable enable public class A { public static object? F; public static void M(object o) { } }"; var comp = CreateCompilation(source0); comp.VerifyDiagnostics(); var ref0 = comp.EmitToImageReference(); var source1 = @"public class B { static void Main() { #nullable enable A.M(A.F); } }"; comp = CreateCompilation( source1, references: new[] { ref0 }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), parseOptions: TestOptions.Regular8.WithNullablePublicOnly()); comp.VerifyDiagnostics( // (6,13): warning CS8604: Possible null reference argument for parameter 'o' in 'void A.M(object o)'. // A.M(A.F); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "A.F").WithArguments("o", "void A.M(object o)").WithLocation(6, 13)); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void NullableEnabled_AllNullableAttributeDefinitions_01() { var source = @"#nullable enable public class Program { }"; var options = WithNullableDisable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; CSharpTestSource sources = new[] { NullableAttributeDefinition, NullableContextAttributeDefinition, NullablePublicOnlyAttributeDefinition, source }; var comp = CreateCompilation(sources, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, publicDefinition: true)); comp = CreateCompilation(sources, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, publicDefinition: true)); } [Fact] public void NullableEnabled_AllNullableAttributeDefinitions_02() { var source = @"#nullable enable public class Program { public object F() => null!; }"; var options = WithNullableDisable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; CSharpTestSource sources = new[] { NullableAttributeDefinition, NullableContextAttributeDefinition, NullablePublicOnlyAttributeDefinition, source }; var comp = CreateCompilation(sources, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, publicDefinition: true)); comp = CreateCompilation(sources, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: true, publicDefinition: true)); } [Fact] public void NullableEnabled_OtherNullableAttributeDefinitions_01() { var source = @"#nullable enable public class Program { }"; var options = WithNullableDisable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; CSharpTestSource sources = new[] { NullableAttributeDefinition, NullableContextAttributeDefinition, source }; var comp = CreateCompilation(sources, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(sources, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void NullableEnabled_OtherNullableAttributeDefinitions_02() { var source = @"#nullable enable public class Program { public object F() => null!; }"; var options = WithNullableDisable().WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; CSharpTestSource sources = new[] { NullableAttributeDefinition, NullableContextAttributeDefinition, source }; var comp = CreateCompilation(sources, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(sources, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNullablePublicOnlyAttribute); } [Fact] public void LocalFunctionReturnType_SynthesizedAttributeDefinitions() { var source = @"public class Program { static void Main() { #nullable enable object? L() => null; L(); } }"; var options = TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; var comp = CreateCompilation(source, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); comp = CreateCompilation(source, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: AssertNoNullablePublicOnlyAttribute); } [Fact] public void LocalFunctionReturnType_ExplicitAttributeDefinitions() { var source = @"public class Program { static void Main() { #nullable enable object? L() => null; L(); } }"; var options = TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All); var parseOptions = TestOptions.Regular8; CSharpTestSource sources = new[] { NullableAttributeDefinition, NullableContextAttributeDefinition, NullablePublicOnlyAttributeDefinition, source }; var comp = CreateCompilation(sources, options: options, parseOptions: parseOptions); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, publicDefinition: true)); comp = CreateCompilation(sources, options: options, parseOptions: parseOptions.WithNullablePublicOnly()); CompileAndVerify(comp, symbolValidator: m => AssertNullablePublicOnlyAttribute(m, includesAttributeDefinition: true, includesAttributeUse: false, publicDefinition: true)); } [Fact] [WorkItem(36457, "https://github.com/dotnet/roslyn/issues/36457")] public void ExplicitAttribute_ReferencedInSource_Assembly() { var sourceAttribute = @"namespace System.Runtime.CompilerServices { internal class NullablePublicOnlyAttribute : System.Attribute { internal NullablePublicOnlyAttribute(bool b) { } } }"; var source = @"using System.Runtime.CompilerServices; [assembly: NullablePublicOnly(false)] [module: NullablePublicOnly(false)] "; // C#7 var comp = CreateCompilation(new[] { sourceAttribute, source }, parseOptions: TestOptions.Regular7); verifyDiagnostics(comp); // C#8 comp = CreateCompilation(new[] { sourceAttribute, source }); verifyDiagnostics(comp); static void verifyDiagnostics(CSharpCompilation comp) { comp.VerifyDiagnostics( // (3,10): error CS8335: Do not use 'System.Runtime.CompilerServices.NullablePublicOnlyAttribute'. This is reserved for compiler usage. // [module: NullablePublicOnly(false)] Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, "NullablePublicOnly(false)").WithArguments("System.Runtime.CompilerServices.NullablePublicOnlyAttribute").WithLocation(3, 10)); } } [Fact] [WorkItem(36457, "https://github.com/dotnet/roslyn/issues/36457")] public void ExplicitAttribute_ReferencedInSource_Other() { var sourceAttribute = @"namespace System.Runtime.CompilerServices { internal class NullablePublicOnlyAttribute : System.Attribute { internal NullablePublicOnlyAttribute(bool b) { } } }"; var source = @"using System.Runtime.CompilerServices; [NullablePublicOnly(false)] class Program { }"; var comp = CreateCompilation(new[] { sourceAttribute, source }); comp.VerifyDiagnostics(); } [Fact] public void ExplicitAttribute_WithNullableAttribute() { var sourceAttribute = @"#nullable enable namespace System.Runtime.CompilerServices { public class NullablePublicOnlyAttribute : System.Attribute { public NullablePublicOnlyAttribute(bool b) { } public NullablePublicOnlyAttribute( object x, object? y, #nullable disable object z) { } } }"; var comp = CreateCompilation(sourceAttribute); var ref0 = comp.EmitToImageReference(); var expected = @"System.Runtime.CompilerServices.NullablePublicOnlyAttribute NullablePublicOnlyAttribute(System.Object! x, System.Object? y, System.Object z) [Nullable(1)] System.Object! x [Nullable(2)] System.Object? y "; AssertNullableAttributes(comp, expected); var source = @"#nullable enable public class Program { public object _f1; public object? _f2; #nullable disable public object _f3; }"; comp = CreateCompilation(source, references: new[] { ref0 }); expected = @"Program [Nullable(1)] System.Object! _f1 [Nullable(2)] System.Object? _f2 "; AssertNullableAttributes(comp, expected); } [Fact] [WorkItem(36934, "https://github.com/dotnet/roslyn/issues/36934")] public void AttributeUsage() { var source = @"#nullable enable public class Program { public object? F; }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithNullablePublicOnly(), options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)); CompileAndVerify(comp, symbolValidator: module => { var attributeType = module.GlobalNamespace.GetMember<NamedTypeSymbol>("System.Runtime.CompilerServices.NullablePublicOnlyAttribute"); AttributeUsageInfo attributeUsage = attributeType.GetAttributeUsageInfo(); Assert.False(attributeUsage.Inherited); Assert.False(attributeUsage.AllowMultiple); Assert.True(attributeUsage.HasValidAttributeTargets); Assert.Equal(AttributeTargets.Module, attributeUsage.ValidTargets); }); } [Fact] public void MissingAttributeUsageAttribute() { var source = @"#nullable enable public class Program { public object? F; }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithNullablePublicOnly().WithNoRefSafetyRulesAttribute()); comp.MakeTypeMissing(WellKnownType.System_AttributeUsageAttribute); comp.VerifyEmitDiagnostics( // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute..ctor' Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", ".ctor").WithLocation(1, 1), // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute.AllowMultiple' Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", "AllowMultiple").WithLocation(1, 1), // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute.Inherited' Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", "Inherited").WithLocation(1, 1), // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute..ctor' Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", ".ctor").WithLocation(1, 1), // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute.AllowMultiple' Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", "AllowMultiple").WithLocation(1, 1), // error CS0656: Missing compiler required member 'System.AttributeUsageAttribute.Inherited' Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.AttributeUsageAttribute", "Inherited").WithLocation(1, 1)); } [Fact] public void AttributeField() { var source = @"#nullable enable using System; using System.Linq; using System.Reflection; public class Program { public static void Main(string[] args) { var value = GetAttributeValue(typeof(Program).Assembly.Modules.First()); Console.WriteLine(value == null ? ""<null>"" : value.ToString()); } static bool? GetAttributeValue(Module module) { var attribute = module.GetCustomAttributes(false).SingleOrDefault(a => a.GetType().Name == ""NullablePublicOnlyAttribute""); if (attribute == null) return null; var field = attribute.GetType().GetField(""IncludesInternals""); return (bool)field.GetValue(attribute); } }"; var sourceIVTs = @"using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo(""Other"")]"; var parseOptions = TestOptions.Regular8; CompileAndVerify(source, parseOptions: parseOptions, expectedOutput: "<null>"); CompileAndVerify(source, parseOptions: parseOptions.WithNullablePublicOnly(), expectedOutput: "False"); CompileAndVerify(new[] { source, sourceIVTs }, parseOptions: parseOptions, expectedOutput: "<null>"); CompileAndVerify(new[] { source, sourceIVTs }, parseOptions: parseOptions.WithNullablePublicOnly(), expectedOutput: "True"); } private static void AssertNoNullablePublicOnlyAttribute(ModuleSymbol module) { AssertNullablePublicOnlyAttribute(module, includesAttributeDefinition: false, includesAttributeUse: false, publicDefinition: false); } private static void AssertNullablePublicOnlyAttribute(ModuleSymbol module) { AssertNullablePublicOnlyAttribute(module, includesAttributeDefinition: true, includesAttributeUse: true, publicDefinition: false); } private static void AssertNullablePublicOnlyAttribute(ModuleSymbol module, bool includesAttributeDefinition, bool includesAttributeUse, bool publicDefinition) { const string attributeName = "System.Runtime.CompilerServices.NullablePublicOnlyAttribute"; var type = (NamedTypeSymbol)module.GlobalNamespace.GetMember(attributeName); var attribute = module.GetAttributes().SingleOrDefault(); if (includesAttributeDefinition) { Assert.NotNull(type); } else { Assert.Null(type); if (includesAttributeUse) { type = attribute.AttributeClass; } } if (type is object) { Assert.Equal(publicDefinition ? Accessibility.Public : Accessibility.Internal, type.DeclaredAccessibility); } if (includesAttributeUse) { Assert.Equal(type, attribute.AttributeClass); } else { Assert.Null(attribute); } } private void AssertNullableAttributes(CSharpCompilation comp, string expected) { CompileAndVerify(comp, symbolValidator: module => AssertNullableAttributes(module, expected)); } private static void AssertNullableAttributes(ModuleSymbol module, string expected) { var actual = NullableAttributesVisitor.GetString((PEModuleSymbol)module); AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, actual); } } }