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