Skip to content

Instantly share code, notes, and snippets.

@chsienki
Created December 12, 2020 00:10
Show Gist options
  • Save chsienki/334ec398079988fab97bfd7029cf6736 to your computer and use it in GitHub Desktop.
Save chsienki/334ec398079988fab97bfd7029cf6736 to your computer and use it in GitHub Desktop.
Debuggable runtime generator
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.8.0" />
</ItemGroup>
</Project>
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApp18
{
class Program
{
static void Main(string[] args)
{
var source = @"
public static class Program {
public static void Main(string[] args) {
GeneratedClass.DoThing();
}
}
";
var generatorSource = @"
public class GeneratedClass {
public static void DoThing(){
System.Console.WriteLine(""thing"");
}
}
";
var corLib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var console = MetadataReference.CreateFromFile(typeof(Console).Assembly.Location);
var runtime = MetadataReference.CreateFromFile(Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "System.Runtime.dll"));
SyntaxTree programTree = CSharpSyntaxTree.ParseText(SourceText.From(source, Encoding.UTF8), new CSharpParseOptions(LanguageVersion.Latest), "program.cs");
CSharpCompilation compilation = CSharpCompilation.Create(Guid.NewGuid().ToString(), new[] { programTree }, new[] { corLib, console, runtime }, new CSharpCompilationOptions(OutputKind.ConsoleApplication));
SingleFileTestGenerator testGenerator = new SingleFileTestGenerator(generatorSource);
GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { testGenerator });
driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out _);
var diagnostics = outputCompilation.GetDiagnostics();
var generatorTree = driver.GetRunResult().GeneratedTrees[0];
EmbeddedText et = EmbeddedText.FromSource(generatorTree.FilePath, generatorTree.GetText());
EmbeddedText et2 = EmbeddedText.FromSource(programTree.FilePath, programTree.GetText());
var assemblyStream = new MemoryStream();
var symbolsStream = new MemoryStream();
var result = outputCompilation.Emit(assemblyStream, symbolsStream, embeddedTexts: new[] { et, et2 });
var assemblyBytes = assemblyStream.GetBuffer();
var symbolsBytes = symbolsStream.GetBuffer();
var asm = System.Reflection.Assembly.Load(assemblyBytes, symbolsBytes);
asm.EntryPoint.Invoke(null, new object[] { new string[0] });
}
}
internal class SingleFileTestGenerator : ISourceGenerator
{
private readonly string _content;
private readonly string _hintName;
public SingleFileTestGenerator(string content, string hintName = "generatedFile")
{
_content = content;
_hintName = hintName;
}
public void Execute(GeneratorExecutionContext context)
{
context.AddSource(this._hintName, SourceText.From(_content, Encoding.UTF8));
}
public void Initialize(GeneratorInitializationContext context)
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment