Skip to content

Commit 26cfb28

Browse files
feat: add incremental generator (#1864)
1 parent 48d1256 commit 26cfb28

18 files changed

+1314
-744
lines changed

InterfaceStubGenerator.Shared/Emitter.cs

+414
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System.Collections;
2+
3+
namespace Refit.Generator;
4+
5+
internal static class ImmutableEquatableArray
6+
{
7+
public static ImmutableEquatableArray<T> Empty<T>()
8+
where T : IEquatable<T> => ImmutableEquatableArray<T>.Empty;
9+
10+
public static ImmutableEquatableArray<T> ToImmutableEquatableArray<T>(
11+
this IEnumerable<T>? values
12+
)
13+
where T : IEquatable<T> => values == null ? Empty<T>() : new(values);
14+
}
15+
16+
/// <summary>
17+
/// Provides an immutable list implementation which implements sequence equality.
18+
/// </summary>
19+
internal sealed class ImmutableEquatableArray<T>
20+
: IEquatable<ImmutableEquatableArray<T>>,
21+
IReadOnlyList<T>
22+
where T : IEquatable<T>
23+
{
24+
public static ImmutableEquatableArray<T> Empty { get; } = new(Array.Empty<T>());
25+
26+
private readonly T[] _values;
27+
public T this[int index] => _values[index];
28+
public int Count => _values.Length;
29+
30+
public ImmutableEquatableArray(T[] values) => _values = values;
31+
32+
public ImmutableEquatableArray(IEnumerable<T> values) => _values = values.ToArray();
33+
34+
public T[] AsArray() => _values;
35+
36+
public bool Equals(ImmutableEquatableArray<T>? other) =>
37+
other != null && ((ReadOnlySpan<T>)_values).SequenceEqual(other._values);
38+
39+
public override bool Equals(object? obj) =>
40+
obj is ImmutableEquatableArray<T> other && Equals(other);
41+
42+
public override int GetHashCode()
43+
{
44+
var hash = 0;
45+
foreach (T value in _values)
46+
{
47+
hash = Combine(hash, value.GetHashCode());
48+
}
49+
50+
static int Combine(int h1, int h2)
51+
{
52+
// RyuJIT optimizes this to use the ROL instruction
53+
// Related GitHub pull request: https://github.com/dotnet/coreclr/pull/1830
54+
uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
55+
return ((int)rol5 + h1) ^ h2;
56+
}
57+
58+
return hash;
59+
}
60+
61+
public Enumerator GetEnumerator() => new(_values);
62+
63+
IEnumerator<T> IEnumerable<T>.GetEnumerator() => ((IEnumerable<T>)_values).GetEnumerator();
64+
65+
IEnumerator IEnumerable.GetEnumerator() => _values.GetEnumerator();
66+
67+
public struct Enumerator
68+
{
69+
private readonly T[] _values;
70+
private int _index;
71+
72+
internal Enumerator(T[] values)
73+
{
74+
_values = values;
75+
_index = -1;
76+
}
77+
78+
public bool MoveNext()
79+
{
80+
var newIndex = _index + 1;
81+
82+
if ((uint)newIndex < (uint)_values.Length)
83+
{
84+
_index = newIndex;
85+
return true;
86+
}
87+
88+
return false;
89+
}
90+
91+
public readonly T Current => _values[_index];
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#if ROSLYN_4
2+
using System.Text;
3+
using Microsoft.CodeAnalysis;
4+
using Microsoft.CodeAnalysis.Text;
5+
6+
namespace Refit.Generator;
7+
8+
internal static class IncrementalValuesProviderExtensions
9+
{
10+
/// <summary>
11+
/// Registers an output node into an <see cref="IncrementalGeneratorInitializationContext"/> to output a diagnostic.
12+
/// </summary>
13+
/// <param name="context">The input <see cref="IncrementalGeneratorInitializationContext"/> instance.</param>
14+
/// <param name="diagnostic">The input <see cref="IncrementalValuesProvider{TValues}"/> sequence of diagnostics.</param>
15+
public static void ReportDiagnostics(
16+
this IncrementalGeneratorInitializationContext context,
17+
IncrementalValuesProvider<Diagnostic> diagnostic
18+
)
19+
{
20+
context.RegisterSourceOutput(
21+
diagnostic,
22+
static (context, diagnostic) => context.ReportDiagnostic(diagnostic)
23+
);
24+
}
25+
26+
/// <summary>
27+
/// Registers an output node into an <see cref="IncrementalGeneratorInitializationContext"/> to output diagnostics.
28+
/// </summary>
29+
/// <param name="context">The input <see cref="IncrementalGeneratorInitializationContext"/> instance.</param>
30+
/// <param name="diagnostics">The input <see cref="IncrementalValuesProvider{TValues}"/> sequence of diagnostics.</param>
31+
public static void ReportDiagnostics(
32+
this IncrementalGeneratorInitializationContext context,
33+
IncrementalValueProvider<ImmutableEquatableArray<Diagnostic>> diagnostics
34+
)
35+
{
36+
context.RegisterSourceOutput(
37+
diagnostics,
38+
static (context, diagnostics) =>
39+
{
40+
foreach (var diagnostic in diagnostics)
41+
{
42+
context.ReportDiagnostic(diagnostic);
43+
}
44+
}
45+
);
46+
}
47+
48+
/// <summary>
49+
/// Registers an implementation source output for the provided mappers.
50+
/// </summary>
51+
/// <param name="context">The context, on which the output is registered.</param>
52+
/// <param name="model">The interfaces stubs.</param>
53+
public static void EmitSource(
54+
this IncrementalGeneratorInitializationContext context,
55+
IncrementalValuesProvider<InterfaceModel> model
56+
)
57+
{
58+
context.RegisterImplementationSourceOutput(
59+
model,
60+
static (spc, model) =>
61+
{
62+
var mapperText = Emitter.EmitInterface(model);
63+
spc.AddSource(model.FileName, SourceText.From(mapperText, Encoding.UTF8));
64+
}
65+
);
66+
}
67+
}
68+
#endif

InterfaceStubGenerator.Shared/InterfaceStubGenerator.Shared.projitems

+10
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,17 @@
1010
</PropertyGroup>
1111
<ItemGroup>
1212
<Compile Include="$(MSBuildThisFileDirectory)DiagnosticDescriptors.cs" />
13+
<Compile Include="$(MSBuildThisFileDirectory)Emitter.cs" />
14+
<Compile Include="$(MSBuildThisFileDirectory)ImmutableEquatableArray.cs" />
15+
<Compile Include="$(MSBuildThisFileDirectory)IncrementalValuesProviderExtensions.cs" />
1316
<Compile Include="$(MSBuildThisFileDirectory)InterfaceStubGenerator.cs" />
17+
<Compile Include="$(MSBuildThisFileDirectory)IsExternalInit.cs" />
1418
<Compile Include="$(MSBuildThisFileDirectory)ITypeSymbolExtensions.cs" />
19+
<Compile Include="$(MSBuildThisFileDirectory)Models\ContextGenerationModel.cs" />
20+
<Compile Include="$(MSBuildThisFileDirectory)Models\InterfaceModel.cs" />
21+
<Compile Include="$(MSBuildThisFileDirectory)Models\MethodModel.cs" />
22+
<Compile Include="$(MSBuildThisFileDirectory)Models\ParameterModel.cs" />
23+
<Compile Include="$(MSBuildThisFileDirectory)Models\TypeConstraint.cs" />
24+
<Compile Include="$(MSBuildThisFileDirectory)Parser.cs" />
1525
</ItemGroup>
1626
</Project>

0 commit comments

Comments
 (0)