Skip to content

Commit 8abff00

Browse files
Copilotdex3r
andcommitted
Extract source emitting code into SourceEmitting namespace and refactor ExecutionRuntime
- Create CSharpLiteralFormatter for value/key literal formatting - Create CSharpAccessibilityKeyword for accessibility mapping - Create CSharpTypeKeyword for type kind mapping - Create PartialMethodEmitData record and PartialMethodSourceEmitter - Create DummyImplementationEmitter with data records - Create RoslynSymbolDataMapper to bridge Roslyn types to emitter records - Create GeneratorAssemblyExecutor for shared compile/load logic - Create BodyGenerationDataExtractor for reflection-based data extraction - Refactor GeneratesMethodExecutionRuntime to use new classes - Refactor GeneratesMethodPatternSourceBuilder to delegate to SourceEmitting - Add documentation comments to all internal/public methods Co-authored-by: dex3r <[email protected]> Agent-Logs-Url: https://github.com/dex3r/EasySourceGenerators/sessions/cb205769-20ee-4e1e-9b44-3ef890163968
1 parent b0bcd79 commit 8abff00

14 files changed

Lines changed: 896 additions & 658 deletions
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Reflection;
3+
4+
namespace EasySourceGenerators.Generators.IncrementalGenerators;
5+
6+
/// <summary>
7+
/// Extracts <see cref="FluentBodyResult"/> data from a method result object via reflection.
8+
/// The result object is expected to be a <c>DataMethodBodyGenerator</c> containing a
9+
/// <c>BodyGenerationData</c> property, from which return values and delegate bodies are extracted.
10+
/// </summary>
11+
internal static class BodyGenerationDataExtractor
12+
{
13+
/// <summary>
14+
/// Extracts the return value from a fluent body generator method result using reflection.
15+
/// Checks for <c>ReturnConstantValueFactory</c> first, then <c>RuntimeDelegateBody</c>.
16+
/// Returns a <see cref="FluentBodyResult"/> with the extracted value, or <c>null</c> return value
17+
/// if neither factory nor body are present.
18+
/// </summary>
19+
internal static FluentBodyResult Extract(object methodResult, bool isVoidReturnType)
20+
{
21+
Type resultType = methodResult.GetType();
22+
23+
// The result should be a DataMethodBodyGenerator containing a BodyGenerationData Data property
24+
PropertyInfo? dataProperty = resultType.GetProperty(Consts.BodyGenerationDataPropertyName);
25+
if (dataProperty == null)
26+
{
27+
// The method returned something that isn't a DataMethodBodyGenerator.
28+
// This may happen when the fluent chain is incomplete (e.g., user returned an intermediate builder).
29+
return new FluentBodyResult(null, isVoidReturnType);
30+
}
31+
32+
object? bodyGenerationData = dataProperty.GetValue(methodResult);
33+
if (bodyGenerationData == null)
34+
{
35+
return new FluentBodyResult(null, isVoidReturnType);
36+
}
37+
38+
Type dataType = bodyGenerationData.GetType();
39+
PropertyInfo? returnTypeProperty = dataType.GetProperty("ReturnType");
40+
Type? dataReturnType = returnTypeProperty?.GetValue(bodyGenerationData) as Type;
41+
bool isVoid = dataReturnType == typeof(void);
42+
43+
return TryExtractFromConstantFactory(dataType, bodyGenerationData, isVoid)
44+
?? TryExtractFromRuntimeBody(dataType, bodyGenerationData, isVoid)
45+
?? new FluentBodyResult(null, isVoid);
46+
}
47+
48+
/// <summary>
49+
/// Attempts to extract a return value by invoking the <c>ReturnConstantValueFactory</c> delegate.
50+
/// </summary>
51+
private static FluentBodyResult? TryExtractFromConstantFactory(
52+
Type dataType,
53+
object bodyGenerationData,
54+
bool isVoid)
55+
{
56+
PropertyInfo? constantFactoryProperty = dataType.GetProperty("ReturnConstantValueFactory");
57+
Delegate? constantFactory = constantFactoryProperty?.GetValue(bodyGenerationData) as Delegate;
58+
if (constantFactory == null)
59+
{
60+
return null;
61+
}
62+
63+
object? constantValue = constantFactory.DynamicInvoke();
64+
return new FluentBodyResult(constantValue?.ToString(), isVoid);
65+
}
66+
67+
/// <summary>
68+
/// Attempts to extract a return value by invoking the <c>RuntimeDelegateBody</c> delegate.
69+
/// Only invokes delegates with zero parameters; parameterized delegates cannot be executed
70+
/// at compile time without concrete values.
71+
/// </summary>
72+
private static FluentBodyResult? TryExtractFromRuntimeBody(
73+
Type dataType,
74+
object bodyGenerationData,
75+
bool isVoid)
76+
{
77+
PropertyInfo? runtimeBodyProperty = dataType.GetProperty("RuntimeDelegateBody");
78+
Delegate? runtimeBody = runtimeBodyProperty?.GetValue(bodyGenerationData) as Delegate;
79+
if (runtimeBody == null)
80+
{
81+
return null;
82+
}
83+
84+
ParameterInfo[] bodyParams = runtimeBody.Method.GetParameters();
85+
if (bodyParams.Length == 0)
86+
{
87+
object? bodyResult = runtimeBody.DynamicInvoke();
88+
return new FluentBodyResult(bodyResult?.ToString(), isVoid);
89+
}
90+
91+
// For delegates with parameters, we can't invoke at compile time without values
92+
return new FluentBodyResult(null, isVoid);
93+
}
94+
}

0 commit comments

Comments
 (0)