You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A property's ExpressionBodyFactory runs depth + 3 times (6 at depth 3), so a stateful factory writes different code depending on how deeply its class is nested #202
The expression callback is rendered once to validate it and again to write it, and validation itself is repeated at every nesting level:
PropertyTemplate.Validate renders the expression to check it (CodeBlocker/Templates/PropertyTemplate.cs:101), and WriteTo renders it again (PropertyTemplate.cs:67).
ClassTemplate.WriteTo calls Validate (ClassTemplate.cs:78). That recursively validates every member and nested class (ClassTemplate.cs:122,127). Each nested ClassTemplate.WriteTo then validates its whole subtree again.
AddSourceFile validates all classes (SourceFileTemplate.cs:62). It then calls AddClasses, which validates them a second time (SourceFileTemplate.cs:105).
So a property's callback runs depth + 3 times, though the remarks at PropertyTemplate.cs:92 say "That runs the callback once more". AccessorKind.Expression getters and setters behave the same way.
Standalone class: public int First => 2; and public int Second => 3;
Nested inside Outer and written through AddSourceFile: public int First => 8; and public int Second => 9;
With a counter at depth 3 (Outer > Mid > Inner), each callback ran 6 times.
Expected: First => 0 and Second => 1 in both cases, or at least the same output wherever the class sits.
Why it matters
Factories are user code, and source generators commonly give them side effects: counters for unique names, consuming an enumerator, reporting diagnostics. Those effects repeat a nesting-dependent number of times. Generated names then depend on where a class sits, and diagnostics are duplicated. It is also O(depth) rendering work per property.
Suggested fix
Render each expression callback once and reuse the result. Two ways to do that:
cache the rendered lines for the duration of the outermost WriteTo/AddSourceFile
validate only at the outermost entry point and pass an "already validated" flag down
This fits the pre-rendering #176 proposes for throwing BodyFactories.
Acceptance: a test counts callback invocations for a property in a class nested two or more levels deep and written through AddSourceFile. It expects 1 invocation, or 2 if the documented validation pass is kept.
Activity