using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace XUnitTest.SourceGenerator;
/// <summary>生æˆå™¨æµ‹è¯•宿主。在内å˜ä¸ç¼–译æºç 并驱动增é‡ç”Ÿæˆå™¨ï¼Œæ•获生æˆç»“æžœ</summary>
public static class GeneratorTestHost
{
/// <summary>编译æºç å¹¶è¿è¡Œç”Ÿæˆå™¨</summary>
/// <param name="generator">ç›®æ ‡ç”Ÿæˆå™¨</param>
/// <param name="source">待编译æºç </param>
/// <param name="additionalReferences">é™„åŠ å…ƒæ•°æ®å¼•用</param>
/// <returns>生æˆåŽçš„编译与驱动è¿è¡Œç»“æžœ</returns>
public static (Compilation Compilation, GeneratorDriverRunResult Result) Run(IIncrementalGenerator generator, String source, params MetadataReference[] additionalReferences)
=> RunCore(generator, source, null, additionalReferences);
/// <summary>编译æºç å¹¶è¿è¡Œç”Ÿæˆå™¨ï¼ˆæŒ‡å®šé¢„处ç†ç¬¦å·ï¼‰</summary>
/// <param name="generator">ç›®æ ‡ç”Ÿæˆå™¨</param>
/// <param name="source">待编译æºç </param>
/// <param name="preprocessorSymbols">预处ç†ç¬¦å·</param>
/// <param name="additionalReferences">é™„åŠ å…ƒæ•°æ®å¼•用</param>
/// <returns>生æˆåŽçš„编译与驱动è¿è¡Œç»“æžœ</returns>
public static (Compilation Compilation, GeneratorDriverRunResult Result) RunWithSymbols(IIncrementalGenerator generator, String source, String[] preprocessorSymbols, params MetadataReference[] additionalReferences)
=> RunCore(generator, source, preprocessorSymbols, additionalReferences);
private static readonly Lazy<MetadataReference[]> _platformRefs = new(() =>
{
// 除 CoreLib 外,BCL 类型分散在系统程åºé›†ä¸Ž facade ä¸ï¼ˆå¦‚ System.Runtime 转å‘),
// 内å˜ç¼–译需完整引用è¿è¡Œæ—¶å¹³å°ç¨‹åºé›†ï¼Œé¿å… CS0012/CS0246
var dir = System.IO.Path.GetDirectoryName(typeof(Object).Assembly.Location)!;
var list = new List<MetadataReference>();
foreach (var dll in System.IO.Directory.GetFiles(dir, "*.dll"))
{
var name = System.IO.Path.GetFileNameWithoutExtension(dll);
if (name.Contains("Native")) continue;
if (name.StartsWith("System") || name is "mscorlib" or "netstandard" or "Microsoft.CSharp" or "WindowsBase")
list.Add(MetadataReference.CreateFromFile(dll));
}
return list.ToArray();
});
private static (Compilation Compilation, GeneratorDriverRunResult Result) RunCore(IIncrementalGenerator generator, String source, String[]? preprocessorSymbols, MetadataReference[] additionalReferences)
{
var refs = new List<MetadataReference>(_platformRefs.Value);
foreach (var item in additionalReferences) refs.Add(item);
var options = new CSharpParseOptions(LanguageVersion.Latest, preprocessorSymbols: preprocessorSymbols);
var trees = new[]
{
CSharpSyntaxTree.ParseText("global using System;", options),
CSharpSyntaxTree.ParseText(source, options),
};
var compilation = CSharpCompilation.Create(
"GeneratorTest",
trees,
refs,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
var driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: options);
var updated = driver.RunGeneratorsAndUpdateCompilation(compilation, out var output, out _);
return (output, updated.GetRunResult());
}
/// <summary>获å–生æˆå™¨è¾“å‡ºçš„æºæ–‡ä»¶å—典(æç¤ºå → 文本)</summary>
/// <param name="result">驱动è¿è¡Œç»“æžœ</param>
/// <returns>ç”Ÿæˆæ–‡ä»¶å—å…¸</returns>
public static IDictionary<String, String> GetGeneratedSources(GeneratorDriverRunResult result)
{
var dic = new Dictionary<String, String>();
foreach (var item in result.Results)
{
foreach (var source in item.GeneratedSources)
{
dic[source.HintName] = source.SourceText.ToString();
}
}
return dic;
}
}
|