-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Add a source generator that produces boilerplate-free, GoF-consistent Prototype pattern implementations, generating safe cloning APIs with configurable strategies for mutable references.
The generator lives in PatternKit.Generators and emits self-contained C# with no runtime PatternKit dependency.
Primary goals:
- Generate
Clone()/Copy()methods that are correct and explicit. - Provide safe defaults to avoid aliasing mutable members.
- Support shallow vs deep cloning where deterministically possible.
- Support records and structs cleanly.
Motivation / Problem
Cloning is where bugs go to reproduce:
- shallow clones that accidentally share mutable lists
- “deep clone” promises that lie
- reflection-based cloning that breaks trimming/AOT
We want generator-emitted clones that are:
- deterministic
- reflection-free
- explicit about what is shallow vs deep
Supported Targets (must-have)
The generator must support:
partial classpartial structpartial record classpartial record struct
Proposed User Experience
A) Default clone (safe-by-default)
[Prototype]
public partial record class UserProfile
{
public string Name { get; init; } = "";
public List<string> Tags { get; init; } = new();
}Generated (representative shape):
public partial record class UserProfile
{
public UserProfile Clone();
}Default behavior:
- value types copied
- strings copied (safe)
- mutable reference types produce a diagnostic unless a strategy is provided
B) Per-member strategy
[Prototype]
public partial record class UserProfile
{
public string Name { get; init; } = "";
[PrototypeStrategy(PrototypeCloneStrategy.Clone)]
public List<string> Tags { get; init; } = new();
}Generator emits new List<string>(Tags) for Clone strategy when T is cloneable or has copy ctor patterns (rules below).
C) Custom clone hook
[Prototype]
public partial class Complex
{
public Widget Widget { get; set; }
[PrototypeStrategy(PrototypeCloneStrategy.Custom)]
public Widget Widget2 { get; set; }
private static partial Widget CloneWidget2(Widget value);
}Attributes / Surface Area
Namespace: PatternKit.Generators.Prototype
-
[Prototype]on the prototype typePrototypeMode Mode(default:ShallowWithWarnings)string CloneMethodName(default:Clone)
-
[PrototypeIgnore]exclude a member -
[PrototypeInclude]include only marked members (if IncludeExplicit mode) -
[PrototypeStrategy]per-member strategy
Enums:
PrototypeMode:ShallowWithWarnings,Shallow,DeepWhenPossiblePrototypeCloneStrategy:ByReference,ShallowCopy,Clone,DeepCopy,Custom
Semantics (must-have)
Member selection
- Default: include all eligible instance fields/properties with getters.
- Support include-explicit via
[Prototype(IncludeExplicit=true)](optional if you prefer to split; but consistent with other generators).
Clone construction
-
For records: prefer
with { ... }when feasible. -
Otherwise:
- use copy constructor if available
- else use parameterless ctor + member assignment where writable
If none are possible, emit a diagnostic and do not generate broken code.
Strategies
Baseline rules:
-
value types: copy
-
string: copy
-
reference types:
- default:
ByReferencewith warning underShallowWithWarnings
- default:
Strategy Clone (v1):
-
Supported when:
- type implements
ICloneable(discouraged but common), OR - has an accessible
Clone()method returning same type, OR - has a copy constructor
T(T other)
- type implements
Collections:
-
List<T>with Clone strategy:new List<T>(old)- if
Trequires clone, deep behavior is v2 unless explicitly configured.
Strategy DeepCopy:
- v2 unless very limited and provable.
Strategy Custom:
- requires user-provided partial method
Clone<MemberName>(T value).
Diagnostics (must-have)
Stable IDs, actionable:
PKPRO001Type marked[Prototype]must bepartial.PKPRO002Cannot construct clone target (no supported clone construction path).PKPRO003Unsafe reference capture: member cloned by reference (warning).PKPRO004Requested Clone strategy but no clone mechanism found.PKPRO005Custom strategy requires partial clone hook, but none found.PKPRO006Include/Ignore attribute misuse.
Generated Code Layout
TypeName.Prototype.g.cs
Determinism:
- stable ordering by member name.
Testing Expectations
-
Records clone with
withwhen possible. -
Class clone via ctor+assignment works.
-
Diagnostics:
- missing construction path
- unsafe reference warnings
- missing custom hook
-
Strategy behavior:
- list clone produces new list
- by-reference leaves same reference
Acceptance Criteria
-
[Prototype]works for class/struct/record class/record struct. - Generated clone method is deterministic and reflection-free.
- Safe-by-default warnings for mutable references.
- Per-member strategies supported (ByReference/Clone/Custom v1).
- Diagnostics cover constructibility and strategy gaps.
- Tests cover records, classes, and strategy behaviors.