Skip to content

Commit

Permalink
Make DllImportGenerator emit a GeneratedCodeAttribute on our stubs (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jkoritzinsky authored Mar 2, 2022
1 parent defd20c commit 2330b4b
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@
<type fullname="System.Runtime.InteropServices.GeneratedDllImportAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.CodeDom.Compiler.GeneratedCodeAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>

<!-- The following attributes are generated by the compiler, so they could be in any assembly -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public static bool AreCompilationSettingsEqual(StubEnvironment env1, StubEnviron

internal sealed class DllImportStubContext : IEquatable<DllImportStubContext>
{
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.
Expand Down Expand Up @@ -123,18 +127,31 @@ public static DllImportStubContext Create(

ImmutableArray<AttributeListSyntax>.Builder additionalAttrs = ImmutableArray.CreateBuilder<AttributeListSyntax>();

// 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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<IMethodSymbol>().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<IMethodSymbol>().Single(m => m.Name == "Method");
Assert.DoesNotContain(stubMethod.GetAttributes(), attr => attr.AttributeClass!.ToDisplayString() == typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).FullName);
}

public static IEnumerable<object[]> GetDownlevelTargetFrameworks()
{
yield return new object[] { TestTargetFramework.Net, true };
Expand Down

0 comments on commit 2330b4b

Please sign in to comment.