Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor generators #83

Merged
merged 1 commit into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,12 @@ private static void BuildSource(in SourceProductionContext context, Compilation
.ToArray();
BuildGeneratorOptionsConstructor(in context, symbolsWithAttrData);
BuildCodeBuilderPreProcessorDefinitions(in context, symbolsWithAttrData);
BuildCodeGeneratorExtraCheck(in context, symbolsWithAttrData);
}

public static void BuildGeneratorOptionsConstructor(in SourceProductionContext context, (IPropertySymbol symbol, AttributeData attrData)[] symbolsWithAttrData)
{
const string indent = " ";
StringBuilder sb = new StringBuilder("""
StringBuilder sb = new("""
#nullable enable

namespace FastGenericNew.SourceGenerator;
Expand Down Expand Up @@ -94,7 +93,7 @@ public GeneratorOptions(AnalyzerConfigOptionsProvider? provider)

public static void BuildCodeBuilderPreProcessorDefinitions(in SourceProductionContext context, (IPropertySymbol symbol, AttributeData attrData)[] symbolsWithAttrData)
{
StringBuilder sb = new StringBuilder("""
StringBuilder sb = new("""
#nullable enable

namespace FastGenericNew.SourceGenerator.Utilities;
Expand Down Expand Up @@ -124,41 +123,5 @@ private partial void _Write_PreProcessorDefinitions()
""");
context.AddSource("CodeBuilder.PreProcessor.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}

public static void BuildCodeGeneratorExtraCheck(in SourceProductionContext context, (IPropertySymbol symbol, AttributeData attrData)[] symbolsWithAttrData)
{
const string indent = " ";
StringBuilder sb = new StringBuilder("""
#nullable enable

namespace FastGenericNew.SourceGenerator;

partial class CodeGenerator
{
private static partial bool PreProcessorRelatedCheck(in GeneratorOptions oldValue, in GeneratorOptions newValue) =>

""", 4096);
bool isFirst = true;
foreach (var (symbol, attrData) in symbolsWithAttrData)
{
if (!attrData.TryGetNamedArgument(GeneratorOptionAttributeGenerator.Arg_PresentPreProcessor, out bool value) || !value)
continue;
var propertyName = symbol.Name;
sb.Append(indent);

if (!isFirst)
{
sb.Append("|| ");
}
else isFirst = false;
sb.AppendLine($"oldValue.{propertyName} != newValue.{propertyName}");
}
if (isFirst) sb.Append("false");
sb.Append("""
;
}
""");
context.AddSource("CodeGenerator.PreProcessorRelatedCheck.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}
}
}
18 changes: 10 additions & 8 deletions src/FastGenericNew.SourceGenerator/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ public abstract partial class CodeGenerator
{
public abstract string Filename { get; }

public virtual bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue) =>
oldValue.Namespace != newValue.Namespace
|| oldValue.MaxParameterCount != newValue.MaxParameterCount
|| oldValue.AlertGeneratedFile != newValue.AlertGeneratedFile
|| oldValue.PrettyOutput != newValue.PrettyOutput
|| PreProcessorRelatedCheck(in oldValue, in newValue);

public abstract CodeGenerationResult Generate(in GeneratorOptions options);

private static partial bool PreProcessorRelatedCheck(in GeneratorOptions oldValue, in GeneratorOptions newValue);
public virtual GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return new GeneratorOptions() with
{
Namespace = options.Namespace,
MaxParameterCount = options.MaxParameterCount,
AlertGeneratedFile = options.AlertGeneratedFile,
PrettyOutput = options.PrettyOutput
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,11 @@ public static T CreateInstance()
return builder.BuildAndDispose(this);
}

public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue)
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.ShouldUpdate(oldValue, newValue) && newValue.AllowUnsafeImplementation;
return base.GetOptionsSubset(options) with
{
AllowUnsafeImplementation = options.AllowUnsafeImplementation,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,11 @@ public static T NewOrDefault<
return builder.BuildAndDispose(this);
}

public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue)
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.ShouldUpdate(oldValue, newValue) && newValue.GenerateCreateInstance;
return base.GetOptionsSubset(options) with
{
GenerateCreateInstance = options.GenerateCreateInstance,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,11 @@ public override CodeGenerationResult Generate(in GeneratorOptions options)
return builder.BuildAndDispose(this);
}

public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue) =>
base.ShouldUpdate(oldValue, newValue)
|| oldValue.ForceFastNewDelegate != newValue.ForceFastNewDelegate;
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.GetOptionsSubset(options) with
{
ForceFastNewDelegate = options.ForceFastNewDelegate,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ public override CodeGenerationResult Generate(in GeneratorOptions options)
return builder.BuildAndDispose(this);
}

public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue) =>
base.ShouldUpdate(oldValue, newValue)
|| oldValue.ForceFastNewDelegate != newValue.ForceFastNewDelegate;
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.GetOptionsSubset(options) with
{
ForceFastNewDelegate = options.ForceFastNewDelegate,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ public override CodeGenerationResult Generate(in GeneratorOptions options)
return builder.BuildAndDispose(this);
}

public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue) =>
base.ShouldUpdate(oldValue, newValue)
|| oldValue.PublicFastNew != newValue.PublicFastNew;
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.GetOptionsSubset(options) with
{
PublicFastNew = options.PublicFastNew,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,11 @@ public static bool TryNewOrDefault<
return builder.BuildAndDispose(this);
}

public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue)
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.ShouldUpdate(oldValue, newValue) && newValue.GenerateTryCreateInstance;
return base.GetOptionsSubset(options) with
{
GenerateTryCreateInstance = options.GenerateTryCreateInstance,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ public override CodeGenerationResult Generate(in GeneratorOptions options)
return builder.BuildAndDispose(this);
}

// Since this won't be invoked if the oldValue equals the newValue.
// So just do it.
public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue) => newValue.OutputGenerationInfo;
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.GetOptionsSubset(options) with
{
OutputGenerationInfo = options.OutputGenerationInfo,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ public static T SmartThrowImpl<T>()
return builder.BuildAndDispose(this);
}

public override bool ShouldUpdate(in GeneratorOptions oldValue, in GeneratorOptions newValue) =>
oldValue.Namespace != newValue.Namespace
|| oldValue.AlertGeneratedFile != newValue.AlertGeneratedFile;
public override GeneratorOptions GetOptionsSubset(GeneratorOptions options)
{
return base.GetOptionsSubset(options) with
{
AlertGeneratedFile = options.AlertGeneratedFile,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
<CompilerVisibleProperty Include="FastNew_Namespace" />
<CompilerVisibleProperty Include="FastNew_ForceFastNewDelegate" />
<CompilerVisibleProperty Include="FastNew_AlertGeneratedFile" />
<CompilerVisibleProperty Include="FastNew_DisableGeneratorCache" />
<CompilerVisibleProperty Include="FastNew_PrettyOutput" />
<CompilerVisibleProperty Include="FastNew_MultiThreadedGeneration" />
<CompilerVisibleProperty Include="FastNew_OutputGenerationInfo" />
<CompilerVisibleProperty Include="FastNew_AllowUnsafeImplementation" />
<CompilerVisibleProperty Include="FastNew_PublicFastNew" />
Expand Down
83 changes: 21 additions & 62 deletions src/FastGenericNew.SourceGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,89 +3,48 @@
[Generator(LanguageNames.CSharp)]
public unsafe class Generator : IIncrementalGenerator
{
private static GeneratorOptions _lastOptions;

private static readonly nint[] generatorPointers = Assembly
private static readonly CodeGenerator[] generators = Assembly
.GetCallingAssembly()
.GetTypes()
.Where(static x => !x.IsAbstract && typeof(CodeGenerator).IsAssignableFrom(x))
.Select(static x =>
(nint)
typeof(GeneratorInstance<>)
.MakeGenericType(x)
.GetMethod(nameof(GeneratorInstance<FastNewCoreGenerator>.Generate))
.MethodHandle.GetFunctionPointer()
)
.Select(static x => (CodeGenerator)Activator.CreateInstance(x))
.ToArray();

private static readonly object _lock = new();

public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterSourceOutput(context.AnalyzerConfigOptionsProvider.WithComparer(AnalyzerConfigComparer.Instance), BuildSource);
static void BuildSource(SourceProductionContext sourceContext, AnalyzerConfigOptionsProvider optionsProvider)
foreach (var generator in generators)
{
var newOptions = new GeneratorOptions(optionsProvider);

if (newOptions.DisableGeneratorCache)
{
_lastOptions = default;
}

if (newOptions.MultiThreadedGeneration)
{
Parallel.ForEach(generatorPointers, nativePointer =>
{
var function = (delegate* managed<in GeneratorOptions, in GeneratorOptions, CodeGenerationResult>)nativePointer;
var result = function(in _lastOptions, in newOptions);
if (result.SourceText != null)
{
lock (_lock)
{
sourceContext.AddSource(result.Filename, result.SourceText);
}
}
if (result.Diagnostics != null)
{
lock (_lock)
{
foreach (Diagnostic diag in result.Diagnostics)
{
sourceContext.ReportDiagnostic(diag);
}
}
}
});
}
else
var comparer = new AnalyzerConfigComparer(generator);
context.RegisterSourceOutput(context.AnalyzerConfigOptionsProvider.WithComparer(comparer), (SourceProductionContext sourceContext, AnalyzerConfigOptionsProvider optionsProvider) =>
{
foreach (var nativePointer in generatorPointers)
var options = new GeneratorOptions(optionsProvider);
var result = generator.Generate(in options);
if (result.SourceText != null)
sourceContext.AddSource(result.Filename, result.SourceText);
if (result.Diagnostics != null)
{
var function = (delegate* managed<in GeneratorOptions, in GeneratorOptions, CodeGenerationResult>)nativePointer;
var result = function(in _lastOptions, in newOptions);
if (result.SourceText != null)
sourceContext.AddSource(result.Filename, result.SourceText);
if (result.Diagnostics != null)
foreach (Diagnostic diag in result.Diagnostics)
{
foreach (Diagnostic diag in result.Diagnostics)
{
sourceContext.ReportDiagnostic(diag);
}
sourceContext.ReportDiagnostic(diag);
}
}
}
_lastOptions = newOptions;
});
}
}

class AnalyzerConfigComparer : IEqualityComparer<AnalyzerConfigOptionsProvider>
{
public static readonly AnalyzerConfigComparer Instance = new();
private readonly CodeGenerator generator;

public AnalyzerConfigComparer(CodeGenerator generator)
{
this.generator = generator;
}

public bool Equals(AnalyzerConfigOptionsProvider x, AnalyzerConfigOptionsProvider y) =>
new GeneratorOptions(x).Equals(new GeneratorOptions(y));
generator.GetOptionsSubset(new GeneratorOptions(x)).Equals(generator.GetOptionsSubset(new GeneratorOptions(y)));

public int GetHashCode(AnalyzerConfigOptionsProvider obj) =>
new GeneratorOptions(obj).GetHashCode();
generator.GetOptionsSubset(new GeneratorOptions(obj)).GetHashCode();
}
}
32 changes: 13 additions & 19 deletions src/FastGenericNew.SourceGenerator/GeneratorOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,43 @@
public readonly partial record struct GeneratorOptions
{
[GeneratorOption(16)]
public int MaxParameterCount { get; }
public int MaxParameterCount { get; init; }

[GeneratorOption(false)]
public bool PublicFastNewCore { get; }
public bool PublicFastNewCore { get; init; }

[GeneratorOption(true)]
public bool GenerateTryCreateInstance { get; }
public bool GenerateTryCreateInstance { get; init; }

[GeneratorOption(true)]
public bool GenerateCreateInstance { get; }
public bool GenerateCreateInstance { get; init; }

[GeneratorOption(true)]
public bool GenerateTypeCreateInstance { get; }
public bool GenerateTypeCreateInstance { get; init; }

[GeneratorOption(true)]
public bool NonPublicConstructorSupport { get; }
public bool NonPublicConstructorSupport { get; init; }

[GeneratorOption("FastGenericNew")]
public string Namespace { get; }
public string Namespace { get; init; }

[GeneratorOption(false)]
public bool ForceFastNewDelegate { get; }
public bool ForceFastNewDelegate { get; init; }

[GeneratorOption(true)]
public bool AlertGeneratedFile { get; }

[GeneratorOption(true)]
public bool DisableGeneratorCache { get; }
public bool AlertGeneratedFile { get; init; }

[GeneratorOption(false)]
public bool PrettyOutput { get; }

[GeneratorOption(true)]
public bool MultiThreadedGeneration { get; }
public bool PrettyOutput { get; init; }

[GeneratorOption(false)]
public bool OutputGenerationInfo { get; }
public bool OutputGenerationInfo { get; init; }

[GeneratorOption(false, PresentPreProcessor = true)]
public bool AllowUnsafeImplementation { get; }
public bool AllowUnsafeImplementation { get; init; }

[GeneratorOption(false)]
public bool PublicFastNew { get; }
public bool PublicFastNew { get; init; }

// ctor will be generated by InternalGenerator
//public GeneratorOptions(AnalyzerConfigOptionsProvider? provider)
Expand Down
Loading
Loading