From 30aed5989a1a3e5368895be6c0bbfa6ba71a1d16 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Wed, 25 Oct 2023 11:49:55 -0700 Subject: [PATCH 1/2] Ensure errors are reported when compiler is unable to emit a required attribute. Related to #70338. --- .../Emitter/NoPia/EmbeddedTypesManager.cs | 22 ++- .../Symbols/Attributes/AttributeData.cs | 27 ++-- .../Symbols/Attributes/PEAttributeData.cs | 35 +++++ .../Attributes/RetargetingAttributeData.cs | 35 ++++- .../Symbols/Attributes/SourceAttributeData.cs | 4 + .../Symbols/Source/SourceAssemblySymbol.cs | 3 + .../Source/SynthesizedAttributeData.cs | 2 + .../CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs | 139 +++++++++++++++++- .../Attributes/AttributeTests_Assembly.cs | 33 ++--- .../Emit/NoPia/CommonEmbeddedMember.cs | 6 +- .../Emit/NoPia/CommonEmbeddedMethod.cs | 6 +- .../Emit/NoPia/CommonEmbeddedParameter.cs | 48 +++--- .../Portable/Emit/NoPia/CommonEmbeddedType.cs | 96 ++++++------ .../Emit/NoPia/EmbeddedTypesManager.cs | 10 +- .../Symbols/CommonAttributeDataExtensions.cs | 20 ++- .../Emit/NoPia/EmbeddedTypesManager.vb | 20 ++- .../Symbols/Attributes/AttributeData.vb | 6 +- .../Symbols/Attributes/PEAttributeData.vb | 20 +++ .../Attributes/RetargetingAttributeData.vb | 18 +++ .../Symbols/Attributes/SourceAttributeData.vb | 8 + .../Symbols/Source/SourceAssemblySymbol.vb | 6 + .../SynthesizedAttributeData.vb | 6 + .../Emit/Attributes/AssemblyAttributes.vb | 24 ++- .../Test/Emit/Emit/NoPiaEmbedTypes.vb | 112 +++++++++++++- 24 files changed, 552 insertions(+), 154 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs index a802703114f05..6bbb5febc93ca 100644 --- a/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs +++ b/src/Compilers/CSharp/Portable/Emitter/NoPia/EmbeddedTypesManager.cs @@ -121,7 +121,7 @@ internal override int GetTargetAttributeSignatureIndex(CSharpAttributeData attrD return attrData.GetTargetAttributeSignatureIndex(description); } - internal override CSharpAttributeData CreateSynthesizedAttribute(WellKnownMember constructor, CSharpAttributeData attrData, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) + internal override CSharpAttributeData CreateSynthesizedAttribute(WellKnownMember constructor, ImmutableArray constructorArguments, ImmutableArray> namedArguments, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) { var ctor = GetWellKnownMethod(constructor, syntaxNodeOpt, diagnostics); if ((object)ctor == null) @@ -136,7 +136,7 @@ internal override CSharpAttributeData CreateSynthesizedAttribute(WellKnownMember // the original source interface as both source interface and event provider. Otherwise, we'd have to embed // the event provider class too. return SynthesizedAttributeData.Create(ModuleBeingBuilt.Compilation, ctor, - ImmutableArray.Create(attrData.CommonConstructorArguments[0], attrData.CommonConstructorArguments[0]), + ImmutableArray.Create(constructorArguments[0], constructorArguments[0]), ImmutableArray>.Empty); case WellKnownMember.System_Runtime_InteropServices_CoClassAttribute__ctor: @@ -149,10 +149,26 @@ internal override CSharpAttributeData CreateSynthesizedAttribute(WellKnownMember ImmutableArray>.Empty); default: - return SynthesizedAttributeData.Create(ModuleBeingBuilt.Compilation, ctor, attrData.CommonConstructorArguments, attrData.CommonNamedArguments); + return SynthesizedAttributeData.Create(ModuleBeingBuilt.Compilation, ctor, constructorArguments, namedArguments); } } + internal override bool TryGetAttributeArguments(CSharpAttributeData attrData, out ImmutableArray constructorArguments, out ImmutableArray> namedArguments, SyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) + { + bool result = !attrData.HasErrors; + + constructorArguments = attrData.CommonConstructorArguments; + namedArguments = attrData.CommonNamedArguments; + + DiagnosticInfo errorInfo = attrData.ErrorInfo; + if (errorInfo is not null) + { + diagnostics.Add(errorInfo, syntaxNodeOpt?.Location ?? NoLocation.Singleton); + } + + return result; + } + internal string GetAssemblyGuidString(AssemblySymbol assembly) { Debug.Assert(!IsFrozen); // After we freeze the set of types, we might add additional assemblies into this map without actual guid values. diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs index e05dad76ddfb5..8870f833bcfbf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs @@ -45,6 +45,8 @@ internal abstract partial class CSharpAttributeData : AttributeData [MemberNotNullWhen(true, nameof(AttributeClass), nameof(AttributeConstructor))] internal abstract override bool HasErrors { get; } + internal abstract DiagnosticInfo? ErrorInfo { get; } + internal abstract override bool IsConditionallyOmitted { get; } /// @@ -99,8 +101,6 @@ internal bool IsSecurityAttribute(CSharpCompilation compilation) { if (_lazyIsSecurityAttribute == ThreeState.Unknown) { - Debug.Assert(!this.HasErrors); - // CLI spec (Partition II Metadata), section 21.11 "DeclSecurity : 0x0E" states: // SPEC: If the attribute's type is derived (directly or indirectly) from System.Security.Permissions.SecurityAttribute then // SPEC: it is a security custom attribute and requires special treatment. @@ -110,12 +110,18 @@ internal bool IsSecurityAttribute(CSharpCompilation compilation) // NOTE: We will follow the specification. // NOTE: See Devdiv Bug #13762 "Custom security attributes deriving from SecurityAttribute are not treated as security attributes" for details. - // Well-known type SecurityAttribute is optional. - // Native compiler doesn't generate a use-site error if it is not found, we do the same. - var wellKnownType = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAttribute); - Debug.Assert(AttributeClass is object); - var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; - _lazyIsSecurityAttribute = AttributeClass.IsDerivedFrom(wellKnownType, TypeCompareKind.ConsiderEverything, useSiteInfo: ref discardedUseSiteInfo).ToThreeState(); + if (AttributeClass is object) + { + // Well-known type SecurityAttribute is optional. + // Native compiler doesn't generate a use-site error if it is not found, we do the same. + var wellKnownType = compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAttribute); + var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; + _lazyIsSecurityAttribute = AttributeClass.IsDerivedFrom(wellKnownType, TypeCompareKind.ConsiderEverything, useSiteInfo: ref discardedUseSiteInfo).ToThreeState(); + } + else + { + _lazyIsSecurityAttribute = false.ToThreeState(); + } } return _lazyIsSecurityAttribute.Value(); @@ -668,11 +674,6 @@ internal bool ShouldEmitAttribute(Symbol target, bool isReturnType, bool emittin { Debug.Assert(target is SourceAssemblySymbol || target.ContainingAssembly is SourceAssemblySymbol); - if (HasErrors) - { - throw ExceptionUtilities.Unreachable(); - } - // Attribute type is conditionally omitted if both the following are true: // (a) It has at least one applied/inherited conditional attribute AND // (b) None of conditional symbols are defined in the source file where the given attribute was defined. diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs index fddcef5b54f8a..337d8537ddb92 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs @@ -171,6 +171,41 @@ internal override bool HasErrors } } + internal override DiagnosticInfo? ErrorInfo + { + get + { + if (HasErrors) + { + switch (AttributeConstructor) + { + case { HasUseSiteError: true } attributeConstructor: + return attributeConstructor.GetUseSiteInfo().DiagnosticInfo; + + case { }: + return new CSDiagnosticInfo(ErrorCode.ERR_BogusType, string.Empty); + + default: + switch (AttributeClass) + { + case { HasUseSiteError: true } attributeClass: + return attributeClass.GetUseSiteInfo().DiagnosticInfo; + + case { } attributeClass: + return new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, attributeClass, WellKnownMemberNames.InstanceConstructorName); + + default: + return new CSDiagnosticInfo(ErrorCode.ERR_BogusType, string.Empty); + } + } + } + else + { + return null; + } + } + } + internal override bool IsConditionallyOmitted => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs index 18935a1ff7068..83a204a853c49 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/RetargetingAttributeData.cs @@ -15,19 +15,20 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting internal sealed class RetargetingAttributeData : CSharpAttributeData { private readonly CSharpAttributeData _underlying; - private readonly NamedTypeSymbol _attributeClass; + private readonly NamedTypeSymbol? _attributeClass; private readonly MethodSymbol? _attributeConstructor; private readonly ImmutableArray _constructorArguments; private readonly ImmutableArray> _namedArguments; internal RetargetingAttributeData( CSharpAttributeData underlying, - NamedTypeSymbol attributeClass, + NamedTypeSymbol? attributeClass, MethodSymbol? attributeConstructor, ImmutableArray constructorArguments, ImmutableArray> namedArguments) { Debug.Assert(underlying is SourceAttributeData or SynthesizedAttributeData); + Debug.Assert(attributeClass is object || underlying.HasErrors); _underlying = underlying; _attributeClass = attributeClass; @@ -36,7 +37,7 @@ internal RetargetingAttributeData( _namedArguments = namedArguments; } - public override NamedTypeSymbol AttributeClass => _attributeClass; + public override NamedTypeSymbol? AttributeClass => _attributeClass; public override MethodSymbol? AttributeConstructor => _attributeConstructor; protected internal override ImmutableArray CommonConstructorArguments => _constructorArguments; protected internal override ImmutableArray> CommonNamedArguments => _namedArguments; @@ -46,6 +47,34 @@ internal RetargetingAttributeData( [MemberNotNullWhen(true, nameof(AttributeClass), nameof(AttributeConstructor))] internal override bool HasErrors => _underlying.HasErrors || _attributeConstructor is null; + internal override DiagnosticInfo? ErrorInfo + { + get + { + Debug.Assert(AttributeClass is object || _underlying.HasErrors); + + if (_underlying.HasErrors) + { + return _underlying.ErrorInfo; + } + else if (HasErrors) + { + Debug.Assert(AttributeConstructor is null); + + if (AttributeClass is { HasUseSiteError: true }) + { + return AttributeClass.GetUseSiteInfo().DiagnosticInfo; + } + + return new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, AttributeClass, WellKnownMemberNames.InstanceConstructorName); + } + else + { + return null; + } + } + } + internal override bool IsConditionallyOmitted => _underlying.IsConditionallyOmitted; internal override Location GetAttributeArgumentLocation(int parameterIndex) => _underlying.GetAttributeArgumentLocation(parameterIndex); diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs index 8e3350261f6bf..1f6ea4c0d9d7e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/SourceAttributeData.cs @@ -38,6 +38,8 @@ private SourceAttributeData( bool hasErrors, bool isConditionallyOmitted) { + Debug.Assert(compilation is object); + Debug.Assert(applicationNode is object); Debug.Assert(!isConditionallyOmitted || attributeClass is object && attributeClass.IsConditional); Debug.Assert(!constructorArguments.IsDefault); Debug.Assert(!namedArguments.IsDefault); @@ -193,6 +195,8 @@ internal override bool HasErrors } } + internal override DiagnosticInfo? ErrorInfo => null; // Binder reported errors + protected internal sealed override ImmutableArray CommonConstructorArguments { get { return _constructorArguments; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index 9d299a5075492..b406b9fda8927 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -1335,6 +1335,9 @@ private WellKnownAttributeData ValidateAttributeUsageAndDecodeWellKnownAttribute var totalIndex = i + sourceAttributesCount; CSharpAttributeData attribute = attributesFromNetModules[i]; + + diagnostics.Add(attribute.ErrorInfo, NoLocation.Singleton); + if (!attribute.HasErrors && ValidateAttributeUsageForNetModuleAttribute(attribute, netModuleNames[i], diagnostics, ref uniqueAttributes)) { arguments.Attribute = attribute; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SynthesizedAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SynthesizedAttributeData.cs index 61df8054bb320..7af595625517b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SynthesizedAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SynthesizedAttributeData.cs @@ -48,6 +48,7 @@ internal FromMethodAndArguments(CSharpCompilation compilation, MethodSymbol well protected internal override ImmutableArray CommonConstructorArguments => _arguments; protected internal override ImmutableArray> CommonNamedArguments => _namedArguments; internal override bool HasErrors => false; + internal override DiagnosticInfo? ErrorInfo => null; internal override bool IsConditionallyOmitted => false; internal override Location GetAttributeArgumentLocation(int parameterIndex) => NoLocation.Singleton; @@ -77,6 +78,7 @@ internal FromSourceAttributeData(SourceAttributeData original) protected internal override ImmutableArray CommonConstructorArguments => _original.CommonConstructorArguments; protected internal override ImmutableArray> CommonNamedArguments => _original.CommonNamedArguments; internal override bool HasErrors => _original.HasErrors; + internal override DiagnosticInfo? ErrorInfo => _original.ErrorInfo; internal override bool IsConditionallyOmitted => _original.IsConditionallyOmitted; internal override Location GetAttributeArgumentLocation(int parameterIndex) => _original.GetAttributeArgumentLocation(parameterIndex); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs b/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs index 9091115783073..292e071509e0c 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/NoPiaEmbedTypes.cs @@ -3123,12 +3123,145 @@ public void M1() CompileAndVerify(compilation1.AddReferences(dispIdDefinition), symbolValidator: metadataValidator).VerifyDiagnostics(); - CompileAndVerify(compilation1, symbolValidator: metadataValidator).VerifyDiagnostics(); + compilation1.VerifyEmitDiagnostics( + // error CS0012: The type 'DispIdAttribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'DispId, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("System.Runtime.InteropServices.DispIdAttribute", "DispId, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1) + ); CompileAndVerify(compilation2.AddReferences(dispIdDefinition), symbolValidator: metadataValidator).VerifyDiagnostics(); - // https://github.com/dotnet/roslyn/issues/70338: Going to start failing after https://github.com/dotnet/roslyn/pull/70151 is merged - //CompileAndVerify(compilation2, symbolValidator: metadataValidator).VerifyDiagnostics(); + compilation2.VerifyEmitDiagnostics( + // error CS0012: The type 'DispIdAttribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'DispId, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("System.Runtime.InteropServices.DispIdAttribute", "DispId, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/70338")] + public void DispIdAttribute_03() + { + var empty = CreateCompilation("", options: TestOptions.ReleaseDll).EmitToImageReference(); + + string pia = @" +using System; +using System.Runtime.InteropServices; + +[assembly: ImportedFromTypeLib(""GeneralPIA.dll"")] +[assembly: Guid(""f9c2d51d-4f44-45f0-9eda-c9d599b58257"")] + +[ComImport()] +[Guid(""f9c2d51d-4f44-45f0-9eda-c9d599b58279"")] +public interface ITest30 +{ + [System.Runtime.InteropServices.DispIdAttribute(""124"")] + void M1(); +} +"; + + var piaCompilation = CreateCompilation(pia, references: new[] { empty }, options: TestOptions.ReleaseDll, assemblyName: "Pia"); + + piaCompilation.VerifyDiagnostics( + // (12,53): error CS1503: Argument 1: cannot convert from 'string' to 'int' + // [System.Runtime.InteropServices.DispIdAttribute("124")] + Diagnostic(ErrorCode.ERR_BadArgType, @"""124""").WithArguments("1", "string", "int").WithLocation(12, 53) + ); + + string consumer = @" +class UsePia +{ + public static void Main() + { + } +} + +class UsePia5 : ITest30 +{ + public void M1() + { + } +} +"; + + var compilation1 = CreateCompilation(consumer, options: TestOptions.ReleaseExe, + references: new MetadataReference[] { new CSharpCompilationReference(piaCompilation, embedInteropTypes: true) }); + + System.Action metadataValidator = + delegate (ModuleSymbol module) + { + ((PEModuleSymbol)module).Module.PretendThereArentNoPiaLocalTypes(); + + var itest30 = (PENamedTypeSymbol)module.GlobalNamespace.GetTypeMembers("ITest30").Single(); + + var m1 = (PEMethodSymbol)itest30.GetMembers("M1").Single(); + + Assert.Empty(m1.GetAttributes()); + }; + + CompileAndVerify(compilation1, symbolValidator: metadataValidator); + + CompileAndVerify(compilation1.AddReferences(empty), symbolValidator: metadataValidator); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/70338")] + public void DispIdAttribute_04() + { + string pia = @" +using System; +using System.Runtime.InteropServices; + +[assembly: ImportedFromTypeLib(""GeneralPIA.dll"")] +[assembly: Guid(""f9c2d51d-4f44-45f0-9eda-c9d599b58257"")] + +[ComImport()] +[Guid(""f9c2d51d-4f44-45f0-9eda-c9d599b58279"")] +public interface ITest30 +{ + [System.Runtime.InteropServices.DispIdAttribute(124, Something = 10)] + void M1(); +} +"; + + var piaCompilation = CreateCompilation(pia, options: TestOptions.ReleaseDll, assemblyName: "Pia"); + + piaCompilation.VerifyDiagnostics( + // (12,58): error CS0246: The type or namespace name 'Something' could not be found (are you missing a using directive or an assembly reference?) + // [System.Runtime.InteropServices.DispIdAttribute(124, Something = 10)] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Something").WithArguments("Something").WithLocation(12, 58) + ); + + string consumer = @" +class UsePia +{ + public static void Main() + { + } +} + +class UsePia5 : ITest30 +{ + public void M1() + { + } +} +"; + + var compilation1 = CreateCompilation(consumer, options: TestOptions.ReleaseExe, + references: new MetadataReference[] { new CSharpCompilationReference(piaCompilation, embedInteropTypes: true) }); + + System.Action metadataValidator = + delegate (ModuleSymbol module) + { + ((PEModuleSymbol)module).Module.PretendThereArentNoPiaLocalTypes(); + + var itest30 = (PENamedTypeSymbol)module.GlobalNamespace.GetTypeMembers("ITest30").Single(); + + var m1 = (PEMethodSymbol)itest30.GetMembers("M1").Single(); + + Assert.Empty(m1.GetAttributes()); + }; + + CompileAndVerify(compilation1, symbolValidator: metadataValidator); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs index cbbd6babcec72..5e8a6c51e9b0b 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs @@ -1741,8 +1741,13 @@ public class Test { } var netModuleRef = GetNetModuleWithAssemblyAttributesRef(mod, new[] { TestMetadata.Net40.SystemCore }); var appCompilation = CreateCompilationWithMscorlib40(app, references: new[] { netModuleRef }, options: TestOptions.ReleaseDll); - var diagnostics = appCompilation.GetDiagnostics(); - Assert.False(diagnostics.Any()); + appCompilation.VerifyDiagnostics( + // error CS0012: The type 'ExtensionAttribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. + Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("System.Runtime.CompilerServices.ExtensionAttribute", "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(1, 1) + ); + + appCompilation = CreateCompilationWithMscorlib40(app, references: new[] { netModuleRef, TestMetadata.Net40.SystemCore }, options: TestOptions.ReleaseDll); + appCompilation.VerifyEmitDiagnostics(); } [ConditionalFact(typeof(DesktopOnly)), WorkItem(530585, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530585")] @@ -2298,14 +2303,10 @@ public A1(int a){} var comp2 = CreateCompilation("", references: new[] { moduleWithAttribute }, options: TestOptions.ReleaseDll); - CompileAndVerify(comp2, symbolValidator: (m) => - { - var attrs = m.ContainingAssembly.GetAttributes(); - Assert.Equal(3, attrs.Length); - AssertEx.Equal("System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)", attrs[0].ToString()); - AssertEx.Equal("System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows = true)", attrs[1].ToString()); - AssertEx.Equal("System.Diagnostics.DebuggableAttribute(System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)", attrs[2].ToString()); - }).VerifyDiagnostics(); + comp2.VerifyEmitDiagnostics( + // error CS0012: The type 'A1' is defined in an assembly that is not referenced. You must add a reference to assembly 'A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("A1", "A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1) + ); string attribute2 = @" public class A1 : System.Attribute @@ -2317,14 +2318,10 @@ public A1(){} var comp3 = CreateCompilation("", references: new[] { moduleWithAttribute, attributeDefinition2 }, options: TestOptions.ReleaseDll); - CompileAndVerify(comp3, symbolValidator: (m) => - { - var attrs = m.ContainingAssembly.GetAttributes(); - Assert.Equal(3, attrs.Length); - AssertEx.Equal("System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)", attrs[0].ToString()); - AssertEx.Equal("System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows = true)", attrs[1].ToString()); - AssertEx.Equal("System.Diagnostics.DebuggableAttribute(System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)", attrs[2].ToString()); - }).VerifyDiagnostics(); + comp3.VerifyEmitDiagnostics( + // error CS0656: Missing compiler required member 'A1..ctor' + Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("A1", ".ctor").WithLocation(1, 1) + ); } [Fact] diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs index a16ebc497481c..7c8026f8c83c3 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMember.cs @@ -69,11 +69,11 @@ private ImmutableArray GetAttributes(TPEModuleBuilder moduleBuil foreach (var attrData in GetCustomAttributesToEmit(moduleBuilder)) { - if (TypeManager.IsTargetAttribute(attrData, AttributeDescription.DispIdAttribute)) + if (TypeManager.IsTargetAttribute(attrData, AttributeDescription.DispIdAttribute, out int signatureIndex)) { - if (attrData.CommonConstructorArguments.Length == 1) + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out var constructorArguments, out var namedArguments, syntaxNodeOpt, diagnostics)) { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_DispIdAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_DispIdAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } } else diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs index a2e03b4be7869..d8be954912458 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs @@ -82,11 +82,11 @@ protected sealed override TAttributeData PortAttributeIfNeedTo(TAttributeData at // The constructors might be missing (for example, in metadata case) and doing lookup // will ensure that we report appropriate errors. - if (TypeManager.IsTargetAttribute(attrData, AttributeDescription.LCIDConversionAttribute)) + if (TypeManager.IsTargetAttribute(attrData, AttributeDescription.LCIDConversionAttribute, out int signatureIndex)) { - if (attrData.CommonConstructorArguments.Length == 1) + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out var constructorArguments, out var namedArguments, syntaxNodeOpt, diagnostics)) { - return TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_LCIDConversionAttribute__ctor, attrData, syntaxNodeOpt, diagnostics); + return TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_LCIDConversionAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics); } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs index 70a48ff6c3f32..dc38a61bcc9a4 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedParameter.cs @@ -69,9 +69,9 @@ protected TEmbeddedTypesManager TypeManager protected abstract ushort Index { get; } protected abstract IEnumerable GetCustomAttributesToEmit(TPEModuleBuilder moduleBuilder); - private bool IsTargetAttribute(TAttributeData attrData, AttributeDescription description) + private bool IsTargetAttribute(TAttributeData attrData, AttributeDescription description, out int signatureIndex) { - return TypeManager.IsTargetAttribute(attrData, description); + return TypeManager.IsTargetAttribute(attrData, description, out signatureIndex); } private ImmutableArray GetAttributes(TPEModuleBuilder moduleBuilder, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) @@ -86,41 +86,39 @@ private ImmutableArray GetAttributes(TPEModuleBuilder moduleBuil foreach (var attrData in GetCustomAttributesToEmit(moduleBuilder)) { - if (IsTargetAttribute(attrData, AttributeDescription.ParamArrayAttribute)) + int signatureIndex; + ImmutableArray constructorArguments; + ImmutableArray> namedArguments; + + if (IsTargetAttribute(attrData, AttributeDescription.ParamArrayAttribute, out signatureIndex)) { - if (attrData.CommonConstructorArguments.Length == 0) + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_ParamArrayAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_ParamArrayAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } } - else if (IsTargetAttribute(attrData, AttributeDescription.DateTimeConstantAttribute)) + else if (IsTargetAttribute(attrData, AttributeDescription.DateTimeConstantAttribute, out signatureIndex)) { - if (attrData.CommonConstructorArguments.Length == 1) + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } } - else + else if (IsTargetAttribute(attrData, AttributeDescription.DecimalConstantAttribute, out signatureIndex)) { - int signatureIndex = TypeManager.GetTargetAttributeSignatureIndex(attrData, AttributeDescription.DecimalConstantAttribute); - if (signatureIndex != -1) + if ((signatureIndex == 0 || signatureIndex == 1) && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - Debug.Assert(signatureIndex == 0 || signatureIndex == 1); - - if (attrData.CommonConstructorArguments.Length == 5) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute( - signatureIndex == 0 ? WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor : - WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctorByteByteInt32Int32Int32, - attrData, syntaxNodeOpt, diagnostics)); - } + builder.AddOptional(TypeManager.CreateSynthesizedAttribute( + signatureIndex == 0 ? WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor : + WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctorByteByteInt32Int32Int32, + constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } - else if (IsTargetAttribute(attrData, AttributeDescription.DefaultParameterValueAttribute)) + } + else if (IsTargetAttribute(attrData, AttributeDescription.DefaultParameterValueAttribute, out signatureIndex)) + { + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - if (attrData.CommonConstructorArguments.Length == 1) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_DefaultParameterValueAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); - } + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_DefaultParameterValueAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs index ba48f19aed246..d902677753c36 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs @@ -80,9 +80,9 @@ protected CommonEmbeddedType(TEmbeddedTypesManager typeManager, TNamedTypeSymbol protected abstract IEnumerable GetCustomAttributesToEmit(TPEModuleBuilder moduleBuilder); protected abstract void ReportMissingAttribute(AttributeDescription description, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics); - private bool IsTargetAttribute(TAttributeData attrData, AttributeDescription description) + private bool IsTargetAttribute(TAttributeData attrData, AttributeDescription description, out int signatureIndex) { - return TypeManager.IsTargetAttribute(attrData, description); + return TypeManager.IsTargetAttribute(attrData, description, out signatureIndex); } private ImmutableArray GetAttributes(TPEModuleBuilder moduleBuilder, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics) @@ -104,78 +104,76 @@ private ImmutableArray GetAttributes(TPEModuleBuilder moduleBuil foreach (var attrData in GetCustomAttributesToEmit(moduleBuilder)) { - if (IsTargetAttribute(attrData, AttributeDescription.GuidAttribute)) + int signatureIndex; + ImmutableArray constructorArguments; + ImmutableArray> namedArguments; + + if (IsTargetAttribute(attrData, AttributeDescription.GuidAttribute, out signatureIndex)) { - string guidString; - if (attrData.TryGetGuidAttributeValue(out guidString)) + if (TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics) && constructorArguments[0].TryGetGuidAttributeValue(out _)) { // If this type has a GuidAttribute, we should emit it. hasGuid = true; - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_GuidAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_GuidAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } } - else if (IsTargetAttribute(attrData, AttributeDescription.ComEventInterfaceAttribute)) + else if (IsTargetAttribute(attrData, AttributeDescription.ComEventInterfaceAttribute, out signatureIndex)) { - if (attrData.CommonConstructorArguments.Length == 2) + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { hasComEventInterfaceAttribute = true; - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_ComEventInterfaceAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_ComEventInterfaceAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } } - else + else if (IsTargetAttribute(attrData, AttributeDescription.InterfaceTypeAttribute, out signatureIndex)) { - int signatureIndex = TypeManager.GetTargetAttributeSignatureIndex(attrData, AttributeDescription.InterfaceTypeAttribute); - if (signatureIndex != -1) + if ((signatureIndex == 0 || signatureIndex == 1) && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - Debug.Assert(signatureIndex == 0 || signatureIndex == 1); - if (attrData.CommonConstructorArguments.Length == 1) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(signatureIndex == 0 ? WellKnownMember.System_Runtime_InteropServices_InterfaceTypeAttribute__ctorInt16 : - WellKnownMember.System_Runtime_InteropServices_InterfaceTypeAttribute__ctorComInterfaceType, - attrData, syntaxNodeOpt, diagnostics)); - } + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(signatureIndex == 0 ? WellKnownMember.System_Runtime_InteropServices_InterfaceTypeAttribute__ctorInt16 : + WellKnownMember.System_Runtime_InteropServices_InterfaceTypeAttribute__ctorComInterfaceType, + constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } - else if (IsTargetAttribute(attrData, AttributeDescription.BestFitMappingAttribute)) + } + else if (IsTargetAttribute(attrData, AttributeDescription.BestFitMappingAttribute, out signatureIndex)) + { + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - if (attrData.CommonConstructorArguments.Length == 1) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_BestFitMappingAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); - } + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_BestFitMappingAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } - else if (IsTargetAttribute(attrData, AttributeDescription.CoClassAttribute)) + } + else if (IsTargetAttribute(attrData, AttributeDescription.CoClassAttribute, out signatureIndex)) + { + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - if (attrData.CommonConstructorArguments.Length == 1) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_CoClassAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); - } + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_CoClassAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } - else if (IsTargetAttribute(attrData, AttributeDescription.FlagsAttribute)) + } + else if (IsTargetAttribute(attrData, AttributeDescription.FlagsAttribute, out signatureIndex)) + { + if (UnderlyingNamedType.IsEnum && signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - if (attrData.CommonConstructorArguments.Length == 0 && UnderlyingNamedType.IsEnum) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_FlagsAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); - } + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_FlagsAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } - else if (IsTargetAttribute(attrData, AttributeDescription.DefaultMemberAttribute)) + } + else if (IsTargetAttribute(attrData, AttributeDescription.DefaultMemberAttribute, out signatureIndex)) + { + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - if (attrData.CommonConstructorArguments.Length == 1) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); - // Embed members matching default member name. - string defaultMember = attrData.CommonConstructorArguments[0].ValueInternal as string; - if (defaultMember != null) - { - EmbedDefaultMembers(defaultMember, syntaxNodeOpt, diagnostics); - } + // Embed members matching default member name. + string defaultMember = constructorArguments[0].ValueInternal as string; + if (defaultMember != null) + { + EmbedDefaultMembers(defaultMember, syntaxNodeOpt, diagnostics); } } - else if (IsTargetAttribute(attrData, AttributeDescription.UnmanagedFunctionPointerAttribute)) + } + else if (IsTargetAttribute(attrData, AttributeDescription.UnmanagedFunctionPointerAttribute, out signatureIndex)) + { + if (signatureIndex == 0 && TypeManager.TryGetAttributeArguments(attrData, out constructorArguments, out namedArguments, syntaxNodeOpt, diagnostics)) { - if (attrData.CommonConstructorArguments.Length == 1) - { - builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_UnmanagedFunctionPointerAttribute__ctor, attrData, syntaxNodeOpt, diagnostics)); - } + builder.AddOptional(TypeManager.CreateSynthesizedAttribute(WellKnownMember.System_Runtime_InteropServices_UnmanagedFunctionPointerAttribute__ctor, constructorArguments, namedArguments, syntaxNodeOpt, diagnostics)); } } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/EmbeddedTypesManager.cs b/src/Compilers/Core/Portable/Emit/NoPia/EmbeddedTypesManager.cs index 1bdcd4e29fc73..a048a1081f78b 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/EmbeddedTypesManager.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/EmbeddedTypesManager.cs @@ -48,7 +48,7 @@ internal abstract partial class EmbeddedTypesManager< where TModuleCompilationState : CommonModuleCompilationState where TEmbeddedTypesManager : EmbeddedTypesManager where TSyntaxNode : SyntaxNode - where TAttributeData : AttributeData, Cci.ICustomAttribute + where TAttributeData : class, Cci.ICustomAttribute where TAssemblySymbol : class where TNamedTypeSymbol : class, TSymbol, Cci.INamespaceTypeReference where TFieldSymbol : class, TSymbol, Cci.IFieldReference @@ -150,12 +150,14 @@ private bool HasNameConflict(HashSet namesOfTopLevelTypes, TEmbeddedType internal abstract int GetTargetAttributeSignatureIndex(TAttributeData attrData, AttributeDescription description); - internal bool IsTargetAttribute(TAttributeData attrData, AttributeDescription description) + internal bool IsTargetAttribute(TAttributeData attrData, AttributeDescription description, out int signatureIndex) { - return GetTargetAttributeSignatureIndex(attrData, description) != -1; + signatureIndex = GetTargetAttributeSignatureIndex(attrData, description); + return signatureIndex != -1; } - internal abstract TAttributeData CreateSynthesizedAttribute(WellKnownMember constructor, TAttributeData attrData, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics); + internal abstract TAttributeData CreateSynthesizedAttribute(WellKnownMember constructor, ImmutableArray constructorArguments, ImmutableArray> namedArguments, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics); + internal abstract bool TryGetAttributeArguments(TAttributeData attrData, out ImmutableArray constructorArguments, out ImmutableArray> namedArguments, TSyntaxNode syntaxNodeOpt, DiagnosticBag diagnostics); internal abstract void ReportIndirectReferencesToLinkedAssemblies(TAssemblySymbol assembly, DiagnosticBag diagnostics); protected abstract void OnGetTypesCompleted(ImmutableArray types, DiagnosticBag diagnostics); diff --git a/src/Compilers/Core/Portable/Symbols/CommonAttributeDataExtensions.cs b/src/Compilers/Core/Portable/Symbols/CommonAttributeDataExtensions.cs index 38655a733ebff..506f1ce133717 100644 --- a/src/Compilers/Core/Portable/Symbols/CommonAttributeDataExtensions.cs +++ b/src/Compilers/Core/Portable/Symbols/CommonAttributeDataExtensions.cs @@ -10,13 +10,21 @@ public static bool TryGetGuidAttributeValue(this AttributeData attrData, out str { if (attrData.CommonConstructorArguments.Length == 1) { - object? value = attrData.CommonConstructorArguments[0].ValueInternal; + return attrData.CommonConstructorArguments[0].TryGetGuidAttributeValue(out guidString); + } + + guidString = null; + return false; + } + + public static bool TryGetGuidAttributeValue(this TypedConstant typedConstant, out string? guidString) + { + object? value = typedConstant.ValueInternal; - if (value == null || value is string) - { - guidString = (string?)value; - return true; - } + if (value == null || value is string) + { + guidString = (string?)value; + return true; } guidString = null; diff --git a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedTypesManager.vb b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedTypesManager.vb index d3bac01a5b78e..94506e01fe2ea 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedTypesManager.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NoPia/EmbeddedTypesManager.vb @@ -85,7 +85,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia Return attrData.GetTargetAttributeSignatureIndex(description) End Function - Friend Overrides Function CreateSynthesizedAttribute(constructor As WellKnownMember, attrData As VisualBasicAttributeData, syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As VisualBasicAttributeData + Friend Overrides Function CreateSynthesizedAttribute(constructor As WellKnownMember, constructorArguments As ImmutableArray(Of TypedConstant), namedArguments As ImmutableArray(Of KeyValuePair(Of String, TypedConstant)), syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As VisualBasicAttributeData Dim ctor = GetWellKnownMethod(constructor, syntaxNodeOpt, diagnostics) If ctor Is Nothing Then Return Nothing @@ -97,7 +97,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia ' the original source interface as both source interface and event provider. Otherwise, we'd have to embed ' the event provider class too. Return New SynthesizedAttributeData(ModuleBeingBuilt.Compilation, ctor, - ImmutableArray.Create(attrData.CommonConstructorArguments(0), attrData.CommonConstructorArguments(0)), + ImmutableArray.Create(constructorArguments(0), constructorArguments(0)), ImmutableArray(Of KeyValuePair(Of String, TypedConstant)).Empty) Case WellKnownMember.System_Runtime_InteropServices_CoClassAttribute__ctor @@ -110,11 +110,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit.NoPia ImmutableArray(Of KeyValuePair(Of String, TypedConstant)).Empty) Case Else - Return New SynthesizedAttributeData(ModuleBeingBuilt.Compilation, ctor, attrData.CommonConstructorArguments, attrData.CommonNamedArguments) + Return New SynthesizedAttributeData(ModuleBeingBuilt.Compilation, ctor, constructorArguments, namedArguments) End Select End Function + Friend Overrides Function TryGetAttributeArguments(attrData As VisualBasicAttributeData, ByRef constructorArguments As ImmutableArray(Of TypedConstant), ByRef namedArguments As ImmutableArray(Of KeyValuePair(Of String, TypedConstant)), syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As Boolean + Dim result As Boolean = Not attrData.HasErrors + + constructorArguments = attrData.CommonConstructorArguments + namedArguments = attrData.CommonNamedArguments + + Dim errorInfo As DiagnosticInfo = attrData.ErrorInfo + If errorInfo IsNot Nothing Then + diagnostics.Add(errorInfo, If(syntaxNodeOpt?.Location, NoLocation.Singleton)) + End If + + Return result + End Function + Friend Function GetAssemblyGuidString(assembly As AssemblySymbol) As String Debug.Assert(Not IsFrozen) ' After we freeze the set of types, we might add additional assemblies into this map without actual guid values. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/AttributeData.vb b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/AttributeData.vb index 391fa7d3eaf8e..1f9f86c88bf17 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/AttributeData.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/AttributeData.vb @@ -60,6 +60,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend MustOverride Overrides ReadOnly Property HasErrors As Boolean + Friend MustOverride ReadOnly Property ErrorInfo As DiagnosticInfo + Friend MustOverride Overrides ReadOnly Property IsConditionallyOmitted As Boolean ''' @@ -528,10 +530,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend Function ShouldEmitAttribute(target As Symbol, isReturnType As Boolean, emittingAssemblyAttributesInNetModule As Boolean) As Boolean Debug.Assert(TypeOf target Is SourceAssemblySymbol OrElse TypeOf target.ContainingAssembly Is SourceAssemblySymbol) - If HasErrors Then - Throw ExceptionUtilities.Unreachable - End If - ' Attribute type is conditionally omitted if both the following are true: ' (a) It has at least one applied conditional attribute AND ' (b) None of conditional symbols are true at the attribute source location. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb index 2e4becd2fc29e..49d368b35393f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb @@ -194,6 +194,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Get End Property + Friend Overrides ReadOnly Property ErrorInfo As DiagnosticInfo + Get + If HasErrors Then + + If AttributeConstructor IsNot Nothing Then + Return If(AttributeConstructor.GetUseSiteInfo().DiagnosticInfo, + ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, String.Empty)) + + ElseIf AttributeClass IsNot Nothing Then + Return If(AttributeClass.GetUseSiteInfo().DiagnosticInfo, + ErrorFactory.ErrorInfo(ERRID.ERR_MissingRuntimeHelper, AttributeClass.MetadataName & "." & WellKnownMemberNames.InstanceConstructorName)) + Else + Return ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, String.Empty) + End If + Else + Return Nothing + End If + End Get + End Property + Friend Overrides ReadOnly Property IsConditionallyOmitted As Boolean Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/RetargetingAttributeData.vb b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/RetargetingAttributeData.vb index 57184f6952452..c14533da6a7b4 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/RetargetingAttributeData.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/RetargetingAttributeData.vb @@ -28,6 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting ByVal constructorArguments As ImmutableArray(Of TypedConstant), ByVal namedArguments As ImmutableArray(Of KeyValuePair(Of String, TypedConstant))) Debug.Assert(TypeOf underlying Is SourceAttributeData OrElse TypeOf underlying Is SynthesizedAttributeData) + Debug.Assert(attributeClass IsNot Nothing OrElse underlying.HasErrors) _underlying = underlying Me._attributeClass = attributeClass @@ -78,6 +79,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting End Get End Property + Friend Overrides ReadOnly Property ErrorInfo As DiagnosticInfo + Get + Debug.Assert(AttributeClass IsNot Nothing OrElse _underlying.HasErrors) + + If _underlying.HasErrors Then + Return _underlying.ErrorInfo + ElseIf HasErrors Then + Debug.Assert(AttributeConstructor Is Nothing) + + Return If(AttributeClass.GetUseSiteInfo().DiagnosticInfo, + ErrorFactory.ErrorInfo(ERRID.ERR_MissingRuntimeHelper, AttributeClass.MetadataName & "." & WellKnownMemberNames.InstanceConstructorName)) + Else + Return Nothing + End If + End Get + End Property + Friend Overrides Function IsTargetAttribute(namespaceName As String, typeName As String, Optional ignoreCase As Boolean = False) As Boolean Return _underlying.IsTargetAttribute(namespaceName, typeName, ignoreCase) End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/SourceAttributeData.vb b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/SourceAttributeData.vb index 458a5a3ac2b3a..ac8af43a1ae21 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/SourceAttributeData.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/SourceAttributeData.vb @@ -36,6 +36,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ByVal namedArgs As ImmutableArray(Of KeyValuePair(Of String, TypedConstant)), ByVal isConditionallyOmitted As Boolean, ByVal hasErrors As Boolean) + Debug.Assert(compilation IsNot Nothing) + Debug.Assert(applicationNode IsNot Nothing) Debug.Assert(attrMethod IsNot Nothing OrElse hasErrors) Me._compilation = compilation @@ -105,6 +107,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property ErrorInfo As DiagnosticInfo + Get + Return Nothing ' Binder reports errors + End Get + End Property + ''' ''' This method finds an attribute by metadata name and signature. The algorithm for signature matching is similar to the one ''' in Module.GetTargetAttributeSignatureIndex. Note, the signature matching is limited to primitive types diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb index be0325b7b9995..71f3fb69f8e0b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb @@ -341,6 +341,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ' That is why we are iterating attributes backwards. For i As Integer = netModuleAttributesCount - 1 To 0 Step -1 Dim attribute As VisualBasicAttributeData = attributesFromNetModules(i) + + Dim errorInfo As DiagnosticInfo = attribute.ErrorInfo + If errorInfo IsNot Nothing Then + diagnostics.Add(errorInfo, NoLocation.Singleton) + End If + If Not attribute.HasErrors AndAlso ValidateAttributeUsageForNetModuleAttribute(attribute, netModuleNames(i), diagnostics, uniqueAttributes) Then arguments.Attribute = attribute arguments.Index = i diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedAttributeData.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedAttributeData.vb index 0662b339730f7..5c654b9edead1 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedAttributeData.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedAttributeData.vb @@ -108,6 +108,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Friend Overrides ReadOnly Property ErrorInfo As DiagnosticInfo + Get + Return Nothing + End Get + End Property + Friend Overrides Function IsTargetAttribute(namespaceName As String, typeName As String, Optional ignoreCase As Boolean = False) As Boolean Return SourceAttributeData.IsTargetAttribute(AttributeClass, namespaceName, typeName, ignoreCase) End Function diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb index 92a839ce3a93b..2aaeffafc3870 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb @@ -2266,13 +2266,11 @@ End Class Dim comp2 = CreateCompilation("", references:={moduleWithAttribute}, options:=TestOptions.ReleaseDll) - CompileAndVerify(comp2, symbolValidator:=Sub(m) - Dim attrs = m.ContainingAssembly.GetAttributes() - Assert.Equal(3, attrs.Length) - AssertEx.Equal("System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)", attrs(0).ToString()) - AssertEx.Equal("System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows:=True)", attrs(1).ToString()) - AssertEx.Equal("System.Diagnostics.DebuggableAttribute(System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)", attrs(2).ToString()) - End Sub).VerifyDiagnostics() + comp2.AssertTheseEmitDiagnostics( + +BC30652: Reference required to assembly 'A1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' containing the type 'A1'. Add one to your project. + + ) Dim attribute2 = @@ -2290,13 +2288,11 @@ End Class Dim comp3 = CreateCompilation("", references:={moduleWithAttribute, attributeDefinition2}, options:=TestOptions.ReleaseDll) - CompileAndVerify(comp3, symbolValidator:=Sub(m) - Dim attrs = m.ContainingAssembly.GetAttributes() - Assert.Equal(3, attrs.Length) - AssertEx.Equal("System.Runtime.CompilerServices.CompilationRelaxationsAttribute(8)", attrs(0).ToString()) - AssertEx.Equal("System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows:=True)", attrs(1).ToString()) - AssertEx.Equal("System.Diagnostics.DebuggableAttribute(System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)", attrs(2).ToString()) - End Sub).VerifyDiagnostics() + comp3.AssertTheseEmitDiagnostics( + +BC35000: Requested operation is not available because the runtime library function 'A1..ctor' is not defined. + + ) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb index 541c0f39a9942..54bfd2b2c17e7 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb @@ -2720,9 +2720,115 @@ End Structure Dim verifier = CompileAndVerify(compilation1.AddReferences(dispIdDefinition), symbolValidator:=validator) AssertTheseDiagnostics(verifier, ()) - ' https://github.com/dotnet/roslyn/issues/70338: Going to start failing after https://github.com/dotnet/roslyn/pull/70151 is merged - 'verifier = CompileAndVerify(compilation1, symbolValidator:=validator) - 'AssertTheseDiagnostics(verifier, ()) + compilation1.AssertTheseEmitDiagnostics( + +BC30652: Reference required to assembly 'DispId, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' containing the type 'DispIdAttribute'. Add one to your project. + + ) + End Sub + + + + Public Sub DispIdAttribute_03() + + Dim empty = CreateCompilation("", targetFramework:=TargetFramework.DesktopLatestExtended).EmitToImageReference() + + Dim pia = + + + + +Public Interface I + + Sub M() +End Interface +]]> + + + Dim piaCompilation = CreateCompilation(pia, references:={empty}, targetFramework:=TargetFramework.DesktopLatestExtended) + + piaCompilation.AssertTheseDiagnostics( + + ~~~~~ +]]> + ) + + Dim sources1 = + + + + Dim validator As Action(Of ModuleSymbol) = Sub([module]) + DirectCast([module], PEModuleSymbol).Module.PretendThereArentNoPiaLocalTypes() + Dim type = [module].GlobalNamespace.GetMember(Of PENamedTypeSymbol)("I") + Dim method = type.GetMember(Of PEMethodSymbol)("M") + Assert.Empty(method.GetAttributes()) + End Sub + + Dim compilation1 = CreateCompilation(sources1, references:={piaCompilation.ToMetadataReference(embedInteropTypes:=True)}, targetFramework:=TargetFramework.DesktopLatestExtended) + + CompileAndVerify(compilation1, symbolValidator:=validator) + + CompileAndVerify(compilation1.AddReferences(empty), symbolValidator:=validator) + End Sub + + + + Public Sub DispIdAttribute_04() + + Dim pia = + + + + +Public Interface I + + Sub M() +End Interface +]]> + + + Dim piaCompilation = CreateCompilation(pia, targetFramework:=TargetFramework.DesktopLatestExtended) + + piaCompilation.AssertTheseDiagnostics( + + ~~~~~~~~~ +]]> + ) + + Dim sources1 = + + + + Dim validator As Action(Of ModuleSymbol) = Sub([module]) + DirectCast([module], PEModuleSymbol).Module.PretendThereArentNoPiaLocalTypes() + Dim type = [module].GlobalNamespace.GetMember(Of PENamedTypeSymbol)("I") + Dim method = type.GetMember(Of PEMethodSymbol)("M") + Assert.Empty(method.GetAttributes()) + End Sub + + Dim compilation1 = CreateCompilation(sources1, references:={piaCompilation.ToMetadataReference(embedInteropTypes:=True)}, targetFramework:=TargetFramework.DesktopLatestExtended) + + CompileAndVerify(compilation1, symbolValidator:=validator) End Sub From 1731c0dd94a1b0b4b4e0b0febd776a08c558b5bc Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Thu, 26 Oct 2023 07:10:11 -0700 Subject: [PATCH 2/2] Update src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs Co-authored-by: Jan Jones --- .../CSharp/Portable/Symbols/Attributes/AttributeData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs index 8870f833bcfbf..c8977a9eb2eb3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs @@ -120,7 +120,7 @@ internal bool IsSecurityAttribute(CSharpCompilation compilation) } else { - _lazyIsSecurityAttribute = false.ToThreeState(); + _lazyIsSecurityAttribute = ThreeState.False; } }