Skip to content

Commit

Permalink
Initial scaffolding for DllImportGenerator
Browse files Browse the repository at this point in the history
  - Includes identification of GeneratedDllImportAttribute
  - Generation of enclosing types for partial methods
  - Basic tests for compilation of generation code
  • Loading branch information
AaronRobinsonMSFT committed Jul 13, 2020
1 parent 5e20ada commit 56076d3
Show file tree
Hide file tree
Showing 11 changed files with 807 additions and 0 deletions.
3 changes: 3 additions & 0 deletions DllImportGenerator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.vs/
**/bin
**/obj
14 changes: 14 additions & 0 deletions DllImportGenerator/Demo/Demo.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>preview</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\DllImportGenerator\DllImportGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
14 changes: 14 additions & 0 deletions DllImportGenerator/Demo/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Demo
{
unsafe class Program
{
static void Main(string[] args)
{
}
}
}
170 changes: 170 additions & 0 deletions DllImportGenerator/DllImportGenerator.Test/CodeSnippets.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;

namespace DllImportGenerator.Test
{
internal static class CodeSnippets
{
/// <summary>
/// Trivial declaration of GeneratedDllImport usage
/// </summary>
public static readonly string TrivialClassDeclarations = @"
using System.Runtime.InteropServices;
partial class Basic
{
[GeneratedDllImportAttribute(""DoesNotExist"")]
public static partial void Method1();
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method2();
[System.Runtime.InteropServices.GeneratedDllImportAttribute(""DoesNotExist"")]
public static partial void Method3();
[System.Runtime.InteropServices.GeneratedDllImport(""DoesNotExist"")]
public static partial void Method4();
}
";
/// <summary>
/// Trivial declaration of GeneratedDllImport usage
/// </summary>
public static readonly string TrivialStructDeclarations = @"
using System.Runtime.InteropServices;
partial struct Basic
{
[GeneratedDllImportAttribute(""DoesNotExist"")]
public static partial void Method1();
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method2();
[System.Runtime.InteropServices.GeneratedDllImportAttribute(""DoesNotExist"")]
public static partial void Method3();
[System.Runtime.InteropServices.GeneratedDllImport(""DoesNotExist"")]
public static partial void Method4();
}
";

/// <summary>
/// Declaration with multiple attributes
/// </summary>
public static readonly string MultipleAttributes = @"
using System;
using System.Runtime.InteropServices;
sealed class DummyAttribute : Attribute
{
public DummyAttribute() { }
}
sealed class Dummy2Attribute : Attribute
{
public Dummy2Attribute(string input) { }
}
partial class Test
{
[DummyAttribute]
[GeneratedDllImport(""DoesNotExist""), Dummy2Attribute(""string value"")]
public static partial void Method();
}
";

/// <summary>
/// Validate nested namespaces are handled
/// </summary>
public static readonly string NestedNamespace = @"
using System.Runtime.InteropServices;
namespace NS
{
namespace InnerNS
{
partial class Test
{
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method1();
}
}
}
namespace NS.InnerNS
{
partial class Test
{
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method2();
}
}
";

/// <summary>
/// Validate nested types are handled.
/// </summary>
public static readonly string NestedTypes = @"
using System.Runtime.InteropServices;
namespace NS
{
partial class OuterClass
{
partial class InnerClass
{
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method();
}
}
partial struct OuterStruct
{
partial struct InnerStruct
{
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method();
}
}
partial class OuterClass
{
partial struct InnerStruct
{
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method();
}
}
partial struct OuterStruct
{
partial class InnerClass
{
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method();
}
}
}
";

/// <summary>
/// Declaration with user defined EntryPoint.
/// </summary>
public static readonly string UserDefinedEntryPoint = @"
using System.Runtime.InteropServices;
partial class Test
{
[GeneratedDllImport(""DoesNotExist"", EntryPoint=""UserDefinedEntryPoint"")]
public static partial void NotAnExport();
}
";

/// <summary>
/// Declaration with default parameters.
/// </summary>
public static readonly string DefaultParameters = @"
using System.Runtime.InteropServices;
partial class Test
{
[GeneratedDllImport(""DoesNotExist"")]
public static partial void Method(int t = 0);
}
";
}
}
55 changes: 55 additions & 0 deletions DllImportGenerator/DllImportGenerator.Test/Compiles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Xunit;

namespace DllImportGenerator.Test
{
public class Compiles
{
public static IEnumerable<object[]> CodeSnippetsToCompile()
{
yield return new[] { CodeSnippets.TrivialClassDeclarations };
yield return new[] { CodeSnippets.TrivialStructDeclarations };
yield return new[] { CodeSnippets.MultipleAttributes };
yield return new[] { CodeSnippets.NestedNamespace };
yield return new[] { CodeSnippets.NestedTypes };
yield return new[] { CodeSnippets.UserDefinedEntryPoint };
yield return new[] { CodeSnippets.DefaultParameters };
}

[Theory]
[MemberData(nameof(CodeSnippetsToCompile))]
public void ValidateSnippets(string source)
{
Compilation comp = CreateCompilation(source);

var newComp = RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.DllImportGenerator());
Assert.Empty(generatorDiags);

var newCompDiags = newComp.GetDiagnostics();
Assert.Empty(newCompDiags);
}

private static Compilation CreateCompilation(string source, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
=> CSharpCompilation.Create("compilation",
new[] { CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)) },
new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
new CSharpCompilationOptions(outputKind));

private static GeneratorDriver CreateDriver(Compilation c, params ISourceGenerator[] generators)
=> new CSharpGeneratorDriver(c.SyntaxTrees.First().Options,
ImmutableArray.Create(generators),
null,
ImmutableArray<AdditionalText>.Empty);

private static Compilation RunGenerators(Compilation c, out ImmutableArray<Diagnostic> diagnostics, params ISourceGenerator[] generators)
{
CreateDriver(c, generators).RunFullGeneration(c, out var d, out diagnostics);
return d;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>Preview</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.7.0-3.final" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.0-beta1.final" PrivateAssets="all" />
<PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="3.7.0-3.final">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DllImportGenerator\DllImportGenerator.csproj" />
</ItemGroup>

</Project>
37 changes: 37 additions & 0 deletions DllImportGenerator/DllImportGenerator.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30204.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator", "DllImportGenerator\DllImportGenerator.csproj", "{0E14E01F-A582-4D22-8737-BF9DE5270435}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator.Test", "DllImportGenerator.Test\DllImportGenerator.Test.csproj", "{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo\Demo.csproj", "{E478EE77-E072-4A42-B453-EBFDA7728717}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0E14E01F-A582-4D22-8737-BF9DE5270435}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0E14E01F-A582-4D22-8737-BF9DE5270435}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0E14E01F-A582-4D22-8737-BF9DE5270435}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0E14E01F-A582-4D22-8737-BF9DE5270435}.Release|Any CPU.Build.0 = Release|Any CPU
{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8CA13C4-F41B-4ABD-A9F3-63A02C53B96E}.Release|Any CPU.Build.0 = Release|Any CPU
{E478EE77-E072-4A42-B453-EBFDA7728717}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E478EE77-E072-4A42-B453-EBFDA7728717}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E478EE77-E072-4A42-B453-EBFDA7728717}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E478EE77-E072-4A42-B453-EBFDA7728717}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5344B739-3A02-402A-8777-0D54DEC4F3BA}
EndGlobalSection
EndGlobal
Loading

0 comments on commit 56076d3

Please sign in to comment.