|
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class AttributeTests_Embedded : CSharpTestBase
{
[Fact]
public void ReferencingEmbeddedAttributesFromTheSameAssemblySucceeds()
{
var code = @"
namespace Microsoft.CodeAnalysis
{
internal sealed class EmbeddedAttribute : System.Attribute { }
}
namespace TestReference
{
[Microsoft.CodeAnalysis.Embedded]
internal class TestType1 { }
[Microsoft.CodeAnalysis.EmbeddedAttribute]
internal class TestType2 { }
internal class TestType3 { }
}
class Program
{
public static void Main()
{
var obj1 = new TestReference.TestType1();
var obj2 = new TestReference.TestType2();
var obj3 = new TestReference.TestType3();
}
}";
CreateCompilation(code, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute()).VerifyEmitDiagnostics();
}
[Fact]
public void ReferencingEmbeddedAttributesFromADifferentAssemblyFails_Internal()
{
var reference = CreateCompilation(@"
[assembly:System.Runtime.CompilerServices.InternalsVisibleToAttribute(""Source"")]
namespace Microsoft.CodeAnalysis
{
internal class EmbeddedAttribute : System.Attribute { }
}
namespace TestReference
{
[Microsoft.CodeAnalysis.Embedded]
internal class TestType1 { }
[Microsoft.CodeAnalysis.EmbeddedAttribute]
internal class TestType2 { }
internal class TestType3 { }
}");
var code = @"
class Program
{
public static void Main()
{
var obj1 = new TestReference.TestType1();
var obj2 = new TestReference.TestType2();
var obj3 = new TestReference.TestType3(); // This should be fine
}
}";
CreateCompilation(code, references: new[] { reference.ToMetadataReference() }, assemblyName: "Source").VerifyDiagnostics(
// (6,38): error CS0234: The type or namespace name 'TestType1' does not exist in the namespace 'TestReference' (are you missing an assembly reference?)
// var obj1 = new TestReference.TestType1();
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestType1").WithArguments("TestType1", "TestReference").WithLocation(6, 38),
// (7,38): error CS0234: The type or namespace name 'TestType2' does not exist in the namespace 'TestReference' (are you missing an assembly reference?)
// var obj2 = new TestReference.TestType2();
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestType2").WithArguments("TestType2", "TestReference").WithLocation(7, 38));
}
[Fact]
public void ReferencingEmbeddedAttributesFromADifferentAssemblyFails_Module()
{
var module = CreateCompilation(@"
namespace Microsoft.CodeAnalysis
{
internal sealed class EmbeddedAttribute : System.Attribute { }
}
namespace TestReference
{
[Microsoft.CodeAnalysis.Embedded]
internal class TestType1 { }
[Microsoft.CodeAnalysis.EmbeddedAttribute]
internal class TestType2 { }
internal class TestType3 { }
}", options: TestOptions.ReleaseModule);
var reference = ModuleMetadata.CreateFromImage(module.EmitToArray()).GetReference();
var code = @"
class Program
{
public static void Main()
{
var obj1 = new TestReference.TestType1();
var obj2 = new TestReference.TestType2();
var obj3 = new TestReference.TestType3(); // This should be fine
}
}";
CreateCompilation(code, references: new[] { reference }, assemblyName: "Source").VerifyDiagnostics(
// (6,38): error CS0234: The type or namespace name 'TestType1' does not exist in the namespace 'TestReference' (are you missing an assembly reference?)
// var obj1 = new TestReference.TestType1();
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestType1").WithArguments("TestType1", "TestReference").WithLocation(6, 38),
// (7,38): error CS0234: The type or namespace name 'TestType2' does not exist in the namespace 'TestReference' (are you missing an assembly reference?)
// var obj2 = new TestReference.TestType2();
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestType2").WithArguments("TestType2", "TestReference").WithLocation(7, 38));
}
[Fact]
public void ReferencingEmbeddedAttributesFromADifferentAssemblyFails_Public()
{
var reference = CreateCompilation(@"
namespace Microsoft.CodeAnalysis
{
internal class EmbeddedAttribute : System.Attribute { }
}
namespace TestReference
{
[Microsoft.CodeAnalysis.Embedded]
public class TestType1 { }
[Microsoft.CodeAnalysis.EmbeddedAttribute]
public class TestType2 { }
public class TestType3 { }
}");
var code = @"
class Program
{
public static void Main()
{
var obj1 = new TestReference.TestType1();
var obj2 = new TestReference.TestType2();
var obj3 = new TestReference.TestType3(); // This should be fine
}
}";
CreateCompilation(code, references: new[] { reference.ToMetadataReference() }).VerifyDiagnostics(
// (6,38): error CS0234: The type or namespace name 'TestType1' does not exist in the namespace 'TestReference' (are you missing an assembly reference?)
// var obj1 = new TestReference.TestType1();
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestType1").WithArguments("TestType1", "TestReference").WithLocation(6, 38),
// (7,38): error CS0234: The type or namespace name 'TestType2' does not exist in the namespace 'TestReference' (are you missing an assembly reference?)
// var obj2 = new TestReference.TestType2();
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "TestType2").WithArguments("TestType2", "TestReference").WithLocation(7, 38));
}
[Fact]
public void EmbeddedAttributeInSourceIsAllowedIfCompilerDoesNotNeedToGenerateOne()
{
var code = @"
namespace Microsoft.CodeAnalysis
{
internal sealed class EmbeddedAttribute : System.Attribute { }
}
namespace OtherNamespace
{
[Microsoft.CodeAnalysis.EmbeddedAttribute]
public class TestReference
{
public static int GetValue() => 3;
}
}
class Test
{
public static void Main()
{
// This should be fine, as the compiler doesn't need to use an embedded attribute for this compilation
System.Console.Write(OtherNamespace.TestReference.GetValue());
}
}";
CompileAndVerify(code, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), verify: Verification.Passes, expectedOutput: "3");
}
[Theory]
[CombinatorialData]
public void EmbeddedAttributeFromSourceValidation_Valid(
[CombinatorialValues("internal", "public")] string ctorAccessModifier,
[CombinatorialValues(
"System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Interface | System.AttributeTargets.Enum | System.AttributeTargets.Delegate",
"System.AttributeTargets.All",
"")]
string targetsList)
{
var targets = targetsList != "" ? $", System.AttributeUsage({targetsList})" : "";
var code = $$"""
namespace Microsoft.CodeAnalysis
{
[Embedded{{targets}}]
internal sealed class EmbeddedAttribute : System.Attribute
{
{{ctorAccessModifier}} EmbeddedAttribute() { }
}
}
[Microsoft.CodeAnalysis.Embedded]
public class Test
{
public static void Main()
{
M(1);
}
public static void M(in int p)
{
System.Console.WriteLine("M");
}
}
""";
var verifier = CompileAndVerify(code, targetFramework: TargetFramework.NetStandard20, expectedOutput: "M", symbolValidator: module =>
{
var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName);
Assert.NotNull(embeddedAttribute);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", embeddedAttribute.GetAttributes().Single(a => a.AttributeClass.Name != "AttributeUsageAttribute").AttributeClass.ToTestDisplayString());
});
verifier.VerifyDiagnostics();
var reference = verifier.Compilation.EmitToImageReference();
var comp2 = CreateCompilation("""
Test.M(1);
""", references: [reference], targetFramework: TargetFramework.NetStandard20);
comp2.VerifyDiagnostics(
// (1,1): error CS0103: The name 'Test' does not exist in the current context
// Test.M(1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "Test").WithArguments("Test").WithLocation(1, 1));
comp2 = CreateCompilation("""
public class Test
{
public static void M(in int p) {}
}
""", references: [reference], targetFramework: TargetFramework.NetStandard20);
CompileAndVerify(comp2, symbolValidator: module =>
{
var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName);
Assert.NotNull(embeddedAttribute);
Assert.Equal(["System.Runtime.CompilerServices.CompilerGeneratedAttribute", "Microsoft.CodeAnalysis.EmbeddedAttribute"], embeddedAttribute.GetAttributes().Select(a => a.AttributeClass.ToTestDisplayString()));
}).VerifyDiagnostics();
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_Public()
{
var code = """
namespace Microsoft.CodeAnalysis
{
[Embedded]
public sealed class EmbeddedAttribute : System.Attribute
{
public EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating another EmbeddedAttribute, if we hadn't already defined one
}
}
""";
CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics(
// (4,25): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type.
// public sealed class EmbeddedAttribute : System.Attribute
Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 25));
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_NoSealed()
{
var code = """
namespace Microsoft.CodeAnalysis
{
[Embedded]
internal class EmbeddedAttribute : System.Attribute
{
public EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating another EmbeddedAttribute, if we hadn't already defined one
}
}
""";
CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics(
// (4,20): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type.
// internal class EmbeddedAttribute : System.Attribute
Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 20));
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_File()
{
var code = """
namespace Microsoft.CodeAnalysis
{
[Embedded]
file sealed class EmbeddedAttribute : System.Attribute
{
public EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating another EmbeddedAttribute, if we hadn't already defined one
}
}
""";
var verifier = CompileAndVerify(code, targetFramework: TargetFramework.NetStandard20, symbolValidator: module =>
{
var codeAnalysisNamespace = (NamespaceSymbol)module.GlobalNamespace.GetMember("Microsoft.CodeAnalysis");
var embeddedAttributes = codeAnalysisNamespace.GetMembers("EmbeddedAttribute").Cast<NamedTypeSymbol>().ToArray();
Assert.Equal(2, embeddedAttributes.Length);
var embeddedAttribute = embeddedAttributes.Where(t => !t.IsFileLocal).Single();
Assert.NotNull(embeddedAttribute);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", embeddedAttribute.ToTestDisplayString());
var embeddedAttributeFile = embeddedAttributes.Where(t => t.IsFileLocal).Single();
Assert.NotNull(embeddedAttributeFile);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute@<unknown>", embeddedAttributeFile.ToTestDisplayString());
Assert.NotSame(embeddedAttribute, embeddedAttributeFile);
AssertEx.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute@<unknown>", embeddedAttributeFile.GetAttributes().Single().AttributeClass.ToTestDisplayString());
});
}
[Theory]
[InlineData("private")]
[InlineData("protected")]
[InlineData("protected internal")]
[InlineData("private protected")]
public void EmbeddedAttributeFromSourceValidation_CtorAccessibility(string ctorAccessModifier)
{
var code = $$"""
namespace Microsoft.CodeAnalysis
{
[Embedded]
internal sealed class EmbeddedAttribute : System.Attribute
{
{{ctorAccessModifier}} EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating another EmbeddedAttribute, if we hadn't already defined one
}
}
""";
List<DiagnosticDescription> diagnostics = [
// (4,27): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type.
// internal sealed class EmbeddedAttribute : System.Attribute
Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 27),
];
if (ctorAccessModifier != "private")
{
diagnostics.Add(
// (6,27): warning CS0628: 'EmbeddedAttribute.EmbeddedAttribute()': new protected member declared in sealed type
// private protected EmbeddedAttribute() { }
Diagnostic(ErrorCode.WRN_ProtectedInSealed, "EmbeddedAttribute").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute.EmbeddedAttribute()").WithLocation(6, 10 + ctorAccessModifier.Length)
);
}
CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20)
.VerifyEmitDiagnostics(diagnostics.ToArray());
}
[Theory, CombinatorialData]
public void EmbeddedAttributeFromSourceValidation_MissingEmbeddedAttributeApplicationGeneratesAttributeApplication(bool hasObsolete)
{
var code = $$"""
namespace Microsoft.CodeAnalysis
{
{{(hasObsolete ? "[System.Obsolete]" : "")}}
internal sealed class EmbeddedAttribute : System.Attribute
{
public EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating EmbeddedAttribute if we hadn't defined one
}
}
""";
var comp = CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20);
var embeddedAttribute = comp.Assembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName);
Assert.True(embeddedAttribute.HasCodeAnalysisEmbeddedAttribute);
CompileAndVerify(comp, symbolValidator: static module =>
{
var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName);
Assert.NotNull(embeddedAttribute);
Assert.Equal(["Microsoft.CodeAnalysis.EmbeddedAttribute"], embeddedAttribute.GetAttributes().Where(a => a.AttributeClass.Name != "ObsoleteAttribute").Select(a => a.AttributeClass.ToTestDisplayString()));
})
.VerifyDiagnostics();
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_MissingEmbeddedAttributeApplicationGeneratesAttributeApplication_Partial()
{
var code = """
namespace Microsoft.CodeAnalysis
{
internal sealed partial class EmbeddedAttribute : System.Attribute
{
}
}
""";
var comp = CreateCompilation([code, code]);
var sourceDeclaration = comp.SourceAssembly.GetTypeByMetadataName("Microsoft.CodeAnalysis.EmbeddedAttribute");
Assert.Equal(2, sourceDeclaration.Locations.Length);
CompileAndVerify(comp, symbolValidator: module =>
{
var embeddedAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName);
Assert.NotNull(embeddedAttribute);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", embeddedAttribute.GetAttributes().Single().AttributeClass.ToTestDisplayString());
}).VerifyDiagnostics();
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_Generic()
{
var code = """
namespace Microsoft.CodeAnalysis
{
[Embedded<int>]
internal sealed class EmbeddedAttribute<T> : System.Attribute
{
public EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This should trigger generating another EmbeddedAttribute
}
}
""";
var comp = CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20);
CompileAndVerify(comp, symbolValidator: verifyModule).VerifyDiagnostics();
static void verifyModule(ModuleSymbol module)
{
var nonGenericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName);
Assert.NotNull(nonGenericAttribute);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", nonGenericAttribute.ToTestDisplayString());
var genericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName + "`1");
Assert.NotNull(genericAttribute);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute<T>", genericAttribute.ToTestDisplayString());
var isReadonlyAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.IsReadOnlyAttribute.FullName);
Assert.NotNull(isReadonlyAttribute);
AssertEx.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", isReadonlyAttribute.GetAttributes().Single(a => a.AttributeClass.Name == "EmbeddedAttribute").AttributeClass.ToTestDisplayString());
}
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_Generic_BothDefined()
{
var code = """
namespace Microsoft.CodeAnalysis
{
[Embedded<int>]
internal sealed class EmbeddedAttribute<T> : System.Attribute
{
public EmbeddedAttribute() { }
}
internal sealed class EmbeddedAttribute : System.Attribute {}
}
class Test
{
public void M(in int p)
{
// This would trigger generating another EmbeddedAttribute, if we hadn't already defined one
}
}
""";
var comp = CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20);
CompileAndVerify(comp, symbolValidator: verifyModule).VerifyDiagnostics();
static void verifyModule(ModuleSymbol module)
{
var nonGenericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName);
Assert.NotNull(nonGenericAttribute);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", nonGenericAttribute.ToTestDisplayString());
var genericAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName + "`1");
Assert.NotNull(genericAttribute);
Assert.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute<T>", genericAttribute.ToTestDisplayString());
var isReadonlyAttribute = module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.IsReadOnlyAttribute.FullName);
Assert.NotNull(isReadonlyAttribute);
AssertEx.Equal("Microsoft.CodeAnalysis.EmbeddedAttribute", isReadonlyAttribute.GetAttributes().Single(a => a.AttributeClass.Name == "EmbeddedAttribute").AttributeClass.ToTestDisplayString());
}
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_Static()
{
var code = """
namespace Microsoft.CodeAnalysis
{
[Embedded]
internal sealed static class EmbeddedAttribute : System.Attribute
{
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating another EmbeddedAttribute, if we hadn't already defined one
}
}
""";
CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics(
// (3,6): error CS0616: 'EmbeddedAttribute' is not an attribute class
// [Embedded]
Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Embedded").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(3, 6),
// (4,34): error CS0441: 'EmbeddedAttribute': a type cannot be both static and sealed
// internal sealed static class EmbeddedAttribute : System.Attribute
Diagnostic(ErrorCode.ERR_SealedStaticClass, "EmbeddedAttribute").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(4, 34),
// (4,34): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type.
// internal sealed static class EmbeddedAttribute : System.Attribute
Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 34),
// (4,54): error CS0713: Static class 'EmbeddedAttribute' cannot derive from type 'Attribute'. Static classes must derive from object.
// internal sealed static class EmbeddedAttribute : System.Attribute
Diagnostic(ErrorCode.ERR_StaticDerivedFromNonObject, "System.Attribute").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute", "System.Attribute").WithLocation(4, 54));
}
[Fact]
public void EmbeddedAttributeFromSourceValidation_WrongBaseType()
{
var code = """
namespace Microsoft.CodeAnalysis
{
[Embedded]
internal sealed class EmbeddedAttribute
{
public EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating another EmbeddedAttribute, if we hadn't already defined one
}
}
""";
CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20).VerifyEmitDiagnostics(
// (3,6): error CS0616: 'EmbeddedAttribute' is not an attribute class
// [Embedded]
Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "Embedded").WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(3, 6),
// (4,27): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type.
// internal sealed class EmbeddedAttribute
Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(4, 27));
}
[Theory]
[InlineData("AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Delegate")]
[InlineData("AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Delegate")]
[InlineData("AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate")]
[InlineData("AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate")]
[InlineData("AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum")]
public void EmbeddedAttributeFromSourceValidation_AttributeUsage(string targets)
{
var code = $$"""
using System;
namespace Microsoft.CodeAnalysis
{
[Embedded, AttributeUsage({{targets}})]
internal sealed class EmbeddedAttribute : System.Attribute
{
internal EmbeddedAttribute() { }
}
}
class Test
{
public void M(in int p)
{
// This would trigger generating EmbeddedAttribute if we hadn't defined one
}
}
""";
List<DiagnosticDescription> diagnostics = [];
if (!targets.Contains("Class"))
{
diagnostics.Add(
// (4,6): error CS0592: Attribute 'Embedded' is not valid on this declaration type. It is only valid on 'struct, enum, interface, delegate' declarations.
// [Embedded, AttributeUsage(AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Delegate)]
Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "Embedded").WithArguments("Embedded", "struct, enum, interface, delegate").WithLocation(4, 6)
);
}
diagnostics.Add(
// (5,27): error CS9271: The type 'Microsoft.CodeAnalysis.EmbeddedAttribute' must be non-generic, internal, sealed, non-static, have a parameterless constructor, inherit from System.Attribute, and be able to be applied to any type.
// internal sealed class EmbeddedAttribute : System.Attribute
Diagnostic(ErrorCode.ERR_EmbeddedAttributeMustFollowPattern, "EmbeddedAttribute").WithLocation(5, 27)
);
CreateCompilation(code, assemblyName: "testModule", targetFramework: TargetFramework.NetStandard20)
.VerifyEmitDiagnostics(diagnostics.ToArray());
}
[Fact]
public void EmbeddedAttributeForwardedToAnotherAssemblyShouldTriggerAnError()
{
var reference = CompileIL("""
.assembly extern mscorlib { }
.assembly testRef
{
}
.class public auto ansi beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute
extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
ldarg.0
call instance void [mscorlib]System.Attribute::.ctor()
ret
}
}
""", prependDefaultHeader: false);
var code = @"
[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(Microsoft.CodeAnalysis.EmbeddedAttribute))]
class Test
{
public void M(in int p)
{
// This should trigger generating another EmbeddedAttribute
}
}";
CreateCompilation(code, references: new[] { reference }).VerifyEmitDiagnostics(
// error CS8006: Forwarded type 'EmbeddedAttribute' conflicts with type declared in primary module of this assembly.
Diagnostic(ErrorCode.ERR_ForwardedTypeConflictsWithDeclaration).WithArguments("Microsoft.CodeAnalysis.EmbeddedAttribute").WithLocation(1, 1));
}
[Fact]
public void CompilerShouldIgnorePublicEmbeddedAttributesInReferencedAssemblies()
{
var reference = CompileIL("""
.assembly extern mscorlib { }
.assembly testRef
{
}
.class public auto ansi beforefieldinit OtherNamespace.TestReference
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}
.class public auto ansi beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute
extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
ldarg.0
call instance void [mscorlib]System.Attribute::.ctor()
ret
}
}
""", prependDefaultHeader: false);
var code = @"
class Test
{
// This should trigger generating another EmbeddedAttribute
public void M(in int p)
{
var obj = new OtherNamespace.TestReference(); // This should be fine
}
}";
CompileAndVerify(code, verify: Verification.Passes, references: new[] { reference }, symbolValidator: module =>
{
var attributeName = AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName;
var referenceAttribute = module.GetReferencedAssemblySymbols().Single(assembly => assembly.Name == "testRef").GetTypeByMetadataName(attributeName);
Assert.NotNull(referenceAttribute);
var generatedAttribute = module.ContainingAssembly.GetTypeByMetadataName(attributeName);
Assert.NotNull(generatedAttribute);
Assert.False(referenceAttribute.Equals(generatedAttribute));
});
}
[Fact]
public void SynthesizingAttributeRequiresSystemAttribute_NonExisting()
{
var code = @"
namespace System
{
public class Object {}
public class Void {}
public class ValueType {}
public struct Int32 { }
}
public class Test
{
public void M(in object x) { } // should trigger synthesizing IsReadOnly
}";
CreateEmptyCompilation(code).VerifyEmitDiagnostics(CodeAnalysis.Emit.EmitOptions.Default.WithRuntimeMetadataVersion("v4.0.30319"),
// error CS0518: Predefined type 'System.Attribute' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Attribute").WithLocation(1, 1),
// error CS0518: Predefined type 'System.Attribute' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Attribute").WithLocation(1, 1),
// error CS0518: Predefined type 'System.Attribute' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Attribute").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 SynthesizingAttributeRequiresSystemAttribute_NoSystemObject()
{
var code = @"
namespace System
{
public class Attribute {}
public class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public class ValueType { }
public struct Enum { }
public enum AttributeTargets { }
public class Void {}
public struct Int32 { }
public struct Boolean { }
}
public class Test
{
public object M(in object x) { return x; } // should trigger synthesizing IsReadOnly
}";
CreateEmptyCompilation(code).VerifyEmitDiagnostics(CodeAnalysis.Emit.EmitOptions.Default.WithRuntimeMetadataVersion("v4.0.30319"),
// (4,18): error CS0518: Predefined type 'System.Object' is not defined or imported
// public class Attribute {}
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Attribute").WithArguments("System.Object").WithLocation(4, 18),
// (11,18): error CS0518: Predefined type 'System.Object' is not defined or imported
// public class ValueType { }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ValueType").WithArguments("System.Object").WithLocation(11, 18),
// (14,18): error CS0518: Predefined type 'System.Object' is not defined or imported
// public class Void {}
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Void").WithArguments("System.Object").WithLocation(14, 18),
// (18,14): error CS0518: Predefined type 'System.Object' is not defined or imported
// public class Test
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Test").WithArguments("System.Object").WithLocation(18, 14),
// (20,24): error CS0518: Predefined type 'System.Object' is not defined or imported
// public object M(in object x) { return x; } // should trigger synthesizing IsReadOnly
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "object").WithArguments("System.Object").WithLocation(20, 24),
// (20,12): error CS0518: Predefined type 'System.Object' is not defined or imported
// public object M(in object x) { return x; } // should trigger synthesizing IsReadOnly
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "object").WithArguments("System.Object").WithLocation(20, 12),
// (7,40): error CS0518: Predefined type 'System.Object' is not defined or imported
// public AttributeUsageAttribute(AttributeTargets t) { }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "AttributeTargets").WithArguments("System.Object").WithLocation(7, 40),
// (14,18): error CS1729: 'object' does not contain a constructor that takes 0 arguments
// public class Void {}
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "Void").WithArguments("object", "0").WithLocation(14, 18),
// (4,18): error CS1729: 'object' does not contain a constructor that takes 0 arguments
// public class Attribute {}
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "Attribute").WithArguments("object", "0").WithLocation(4, 18),
// (11,18): error CS1729: 'object' does not contain a constructor that takes 0 arguments
// public class ValueType { }
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "ValueType").WithArguments("object", "0").WithLocation(11, 18),
// (18,14): error CS1729: 'object' does not contain a constructor that takes 0 arguments
// public class Test
Diagnostic(ErrorCode.ERR_BadCtorArgCount, "Test").WithArguments("object", "0").WithLocation(18, 14));
}
[Fact]
public void SynthesizingAttributeRequiresSystemAttribute_NoSystemVoid()
{
var code = @"
namespace System
{
public class Attribute {}
public class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets t) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public class ValueType { }
public struct Int32 { }
public struct Boolean { }
public struct Enum { }
public enum AttributeTargets { }
public class Object {}
}
public class Test
{
public object M(in object x) { return x; } // should trigger synthesizing IsReadOnly
}";
CreateEmptyCompilation(code).VerifyEmitDiagnostics(CodeAnalysis.Emit.EmitOptions.Default.WithRuntimeMetadataVersion("v4.0.30319"),
// (8,42): error CS0518: Predefined type 'System.Void' is not defined or imported
// public bool AllowMultiple { get; set; }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "set;").WithArguments("System.Void").WithLocation(8, 42),
// (9,38): error CS0518: Predefined type 'System.Void' is not defined or imported
// public bool Inherited { get; set; }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "set;").WithArguments("System.Void").WithLocation(9, 38),
// (7,9): error CS0518: Predefined type 'System.Void' is not defined or imported
// public AttributeUsageAttribute(AttributeTargets t) { }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "public AttributeUsageAttribute(AttributeTargets t) { }").WithArguments("System.Void").WithLocation(7, 9),
// (4,18): error CS0518: Predefined type 'System.Void' is not defined or imported
// public class Attribute {}
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Attribute").WithArguments("System.Void").WithLocation(4, 18),
// (11,18): error CS0518: Predefined type 'System.Void' is not defined or imported
// public class ValueType { }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ValueType").WithArguments("System.Void").WithLocation(11, 18),
// (18,14): error CS0518: Predefined type 'System.Void' is not defined or imported
// public class Test
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Test").WithArguments("System.Void").WithLocation(18, 14),
// (7,16): error CS0518: Predefined type 'System.Void' is not defined or imported
// public AttributeUsageAttribute(AttributeTargets t) { }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "AttributeUsageAttribute").WithArguments("System.Void").WithLocation(7, 16),
// error CS0518: Predefined type 'System.Void' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Void").WithLocation(1, 1),
// error CS0518: Predefined type 'System.Void' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Void").WithLocation(1, 1),
// error CS0518: Predefined type 'System.Void' is not defined or imported
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Void").WithLocation(1, 1));
}
[Fact]
public void SynthesizingAttributeRequiresSystemAttribute_NoDefaultConstructor()
{
var code = @"
namespace System
{
public class Object {}
public class Void {}
public class ValueType { }
public struct Int32 { }
public struct Boolean { }
public class Attribute
{
public Attribute(object p) { }
}
public class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets t) : base(null) { }
public bool AllowMultiple { get; set; }
public bool Inherited { get; set; }
}
public struct Enum { }
public enum AttributeTargets { }
}
public class Test
{
public void M(in object x) { } // should trigger synthesizing IsReadOnly
}";
CreateEmptyCompilation(code).VerifyEmitDiagnostics(CodeAnalysis.Emit.EmitOptions.Default.WithRuntimeMetadataVersion("v4.0.30319"),
// error CS1729: 'Attribute' does not contain a constructor that takes 0 arguments
Diagnostic(ErrorCode.ERR_BadCtorArgCount).WithArguments("System.Attribute", "0").WithLocation(1, 1),
// error CS1729: 'Attribute' does not contain a constructor that takes 0 arguments
Diagnostic(ErrorCode.ERR_BadCtorArgCount).WithArguments("System.Attribute", "0").WithLocation(1, 1),
// error CS1729: 'Attribute' does not contain a constructor that takes 0 arguments
Diagnostic(ErrorCode.ERR_BadCtorArgCount).WithArguments("System.Attribute", "0").WithLocation(1, 1));
}
[Fact]
public void EmbeddedTypesInAnAssemblyAreNotExposedExternally()
{
var compilation1 = CreateCompilation(parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), source: @"
namespace Microsoft.CodeAnalysis
{
internal sealed class EmbeddedAttribute : System.Attribute { }
}
[Microsoft.CodeAnalysis.Embedded]
public class TestReference1 { }
public class TestReference2 { }
");
Assert.NotNull(compilation1.GetTypeByMetadataName("TestReference1"));
Assert.NotNull(compilation1.GetTypeByMetadataName("TestReference2"));
var compilation2 = CreateCompilation("", references: new[] { compilation1.EmitToImageReference() });
Assert.Null(compilation2.GetTypeByMetadataName("TestReference1"));
Assert.NotNull(compilation2.GetTypeByMetadataName("TestReference2"));
}
}
}
|