-
Notifications
You must be signed in to change notification settings - Fork 4.8k
/
Copy pathConfigurationBindingGenerator.cs
84 lines (73 loc) · 3.28 KB
/
ConfigurationBindingGenerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//#define LAUNCH_DEBUGGER
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
/// <summary>
/// Generates source code to optimize binding with ConfigurationBinder.
/// </summary>
[Generator]
public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator
{
internal const string ProjectName = "Microsoft.Extensions.Configuration.Binder.SourceGeneration";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
#if LAUNCH_DEBUGGER
if (!System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Launch();
}
#endif
IncrementalValueProvider<CompilationData?> compilationData =
context.CompilationProvider
.Select((compilation, _) => compilation.Options is CSharpCompilationOptions options
? new CompilationData((CSharpCompilation)compilation)
: null);
IncrementalValuesProvider<BinderInvocation> inputCalls = context.SyntaxProvider
.CreateSyntaxProvider(
(node, _) => node is InvocationExpressionSyntax invocation,
BinderInvocation.Create)
.Where(operation => operation is not null);
IncrementalValueProvider<(CompilationData?, ImmutableArray<BinderInvocation>)> inputData = compilationData.Combine(inputCalls.Collect());
context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc));
}
/// <summary>
/// Generates source code to optimize binding with ConfigurationBinder.
/// </summary>
private static void Execute(CompilationData compilationData, ImmutableArray<BinderInvocation> inputCalls, SourceProductionContext context)
{
if (inputCalls.IsDefaultOrEmpty)
{
return;
}
if (compilationData?.LanguageVersionIsSupported is not true)
{
context.ReportDiagnostic(Diagnostic.Create(Parser.Diagnostics.LanguageVersionNotSupported, location: null));
return;
}
Parser parser = new(context, compilationData.TypeSymbols!, inputCalls);
if (parser.GetSourceGenerationSpec() is SourceGenerationSpec { } spec)
{
Emitter emitter = new(context, spec);
emitter.Emit();
}
}
private sealed record CompilationData
{
public bool LanguageVersionIsSupported { get; }
public KnownTypeSymbols? TypeSymbols { get; }
public CompilationData(CSharpCompilation compilation)
{
LanguageVersionIsSupported = compilation.LanguageVersion >= LanguageVersion.CSharp11;
if (LanguageVersionIsSupported)
{
TypeSymbols = new KnownTypeSymbols(compilation);
}
}
}
}
}