diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml index 38f8ffdbae7f02..efd2492becf342 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml @@ -268,6 +268,9 @@ + + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs index 838db08cac9653..0bfc2c0fffebbb 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs @@ -42,6 +42,10 @@ public static bool AreCompilationSettingsEqual(StubEnvironment env1, StubEnviron internal sealed class DllImportStubContext : IEquatable { + private static readonly string GeneratorName = typeof(DllImportGenerator).Assembly.GetName().Name; + + private static readonly string GeneratorVersion = typeof(DllImportGenerator).Assembly.GetName().Version.ToString(); + // We don't need the warnings around not setting the various // non-nullable fields/properties on this type in the constructor // since we always use a property initializer. @@ -123,18 +127,31 @@ public static DllImportStubContext Create( ImmutableArray.Builder additionalAttrs = ImmutableArray.CreateBuilder(); - // Define additional attributes for the stub definition. + if (env.TargetFramework != TargetFramework.Unknown) + { + // Define additional attributes for the stub definition. + additionalAttrs.Add( + AttributeList( + SingletonSeparatedList( + Attribute(ParseName(TypeNames.System_CodeDom_Compiler_GeneratedCodeAttribute), + AttributeArgumentList( + SeparatedList( + new[] + { + AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(GeneratorName))), + AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(GeneratorVersion))) + })))))); + } + if (env.TargetFrameworkVersion >= new Version(5, 0) && !MethodIsSkipLocalsInit(env, method)) { additionalAttrs.Add( AttributeList( - SeparatedList(new[] - { + SingletonSeparatedList( // Adding the skip locals init indiscriminately since the source generator is // targeted at non-blittable method signatures which typically will contain locals // in the generated code. - Attribute(ParseName(TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute)) - }))); + Attribute(ParseName(TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute))))); } return new DllImportStubContext() diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index 2b7fa363edba4b..6cffa1f9daef97 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -67,5 +67,7 @@ public static string MarshalEx(InteropGenerationOptions options) public const string DefaultDllImportSearchPathsAttribute = "System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute"; public const string DllImportSearchPath = "System.Runtime.InteropServices.DllImportSearchPath"; + + public const string System_CodeDom_Compiler_GeneratedCodeAttribute = "System.CodeDom.Compiler.GeneratedCodeAttribute"; } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs index 640ee220f088bf..720a0abaa83223 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs @@ -64,6 +64,57 @@ partial class C Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(SkipLocalsInitAttribute).FullName); } + [ConditionalFact] + public async Task GeneratedCodeAdded() + { + string source = @" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +[assembly:DisableRuntimeMarshalling] +partial class C +{ + [GeneratedDllImportAttribute(""DoesNotExist"")] + public static partial S Method(); +} + +[NativeMarshalling(typeof(Native))] +struct S +{ +} + +struct Native +{ + public Native(S s) { } + public S ToManaged() { return default; } +}"; + Compilation comp = await TestUtils.CreateCompilation(source); + + Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.DllImportGenerator()); + + ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; + IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); + Assert.Contains(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName); + } + + [ConditionalFact] + public async Task GeneratedCodeNotAddedOnForwardingStub() + { + string source = @" +using System.Runtime.InteropServices; +partial class C +{ + [GeneratedDllImportAttribute(""DoesNotExist"")] + public static partial void Method(); +}"; + Compilation comp = await TestUtils.CreateCompilation(source); + + Compilation newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.DllImportGenerator()); + + ITypeSymbol c = newComp.GetTypeByMetadataName("C")!; + IMethodSymbol stubMethod = c.GetMembers().OfType().Single(m => m.Name == "Method"); + Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName); + } + public static IEnumerable GetDownlevelTargetFrameworks() { yield return new object[] { TestTargetFramework.Net, true };