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
Copy file name to clipboardExpand all lines: .claude/CLAUDE.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -50,7 +50,7 @@ A .NET library providing Smart Enums, Value Objects, and Discriminated Unions vi
50
50
| Keyless Smart Enum |`[SmartEnum]`| Type-safe enum without underlying value. Identified by field reference only. |
51
51
| Simple Value Object |`[ValueObject<TKey>]`| Single-value immutable type wrapping one underlying value. |
52
52
| Complex Value Object |`[ComplexValueObject]`| Multi-property immutable type. |
53
-
| Ad-hoc Union |`[Union<T1, T2, ...>]` or `[AdHocUnion(...)]`| "One of" several types. Up to 5 type parameters. Cannot be generic. |
53
+
| Ad-hoc Union |`[Union<T1, T2, ...>]` or `[AdHocUnion(...)]`| "One of" several types. Up to 5 type parameters. Can be generic via `TypeParamRef1`–`TypeParamRef5` placeholders.|
54
54
| Regular Union |`[Union]`| Inheritance-based union. Abstract base with sealed derived types. |
55
55
56
56
All types must be declared as `partial`. Source generators produce: factory methods (`Create`, `TryCreate`, `Validate`), equality members, conversion operators, `Switch`/`Map` pattern matching, `IParsable<T>`/`ISpanParsable<T>` (NET9+), and serialization integration.
@@ -94,6 +94,8 @@ All types must be declared as `partial`. Source generators produce: factory meth
94
94
95
95
**Ad-hoc Unions** (`[Union<T1, T2>]` or `[AdHocUnion(...)]`):
96
96
97
+
- Generic unions: use `TypeParamRef1`–`TypeParamRef5` placeholders (in namespace `Thinktecture`) to reference the union's own type parameters. E.g., `[Union<TypeParamRef1, string>] public partial struct Result<T>`. Nested usage supported (e.g., `List<TypeParamRef1>`). For type parameter members: no implicit/explicit conversion operators (C# limitation), factory methods generated instead.
98
+
-`allows ref struct` is **not supported** on ad-hoc union type parameters (TTRESG073). Ref structs cannot be boxed, which conflicts with equality, `Value` property, and Switch/Map delegate patterns.
97
99
- Stateless types (`TXIsStateless = true`): store only discriminator, not instance. Prefer structs.
98
100
- Backing fields: with 2+ distinct non-stateless reference types, reference types auto-share a single `object? _obj` field (value types keep typed fields). `UseSingleBackingField = true` forces all types (including value types, with boxing) into `_obj`.
99
101
@@ -156,7 +158,7 @@ SyntaxProvider (filter by attribute via ForAttributeWithMetadataName)
156
158
157
159
### Analyzers & Refactorings
158
160
159
-
1.`ThinktectureRuntimeExtensionsAnalyzer` -- 57 diagnostic rules (`TTRESG` prefix) for correct usage
161
+
1.`ThinktectureRuntimeExtensionsAnalyzer` -- 59 diagnostic rules (`TTRESG` prefix) for correct usage
160
162
2.`ThinktectureRuntimeExtensionsInternalUsageAnalyzer` -- Prevents external use of internal APIs
161
163
3.`SwitchMapCompletionRefactoringProvider` -- IDE refactoring (light bulb action) that auto-generates arguments for `Switch`/`Map`/`SwitchPartially`/`MapPartially` method calls on Smart Enums and Unions
Copy file name to clipboardExpand all lines: .claude/guides/IMPLEMENTATION.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -154,7 +154,7 @@ public partial class PriorityLevel<TContext> where TContext : notnull
154
154
155
155
Note: Generated partial declarations do not need to repeat generic constraints -- C# inherits them from the original declaration.
156
156
157
-
**Important**: Ad-hoc unions cannot be generic (the analyzer enforces this via a diagnostic).
157
+
**Important**: Ad-hoc unions can be generic via `TypeParamRef1`–`TypeParamRef5` placeholders. The source generator resolves these placeholders to the union's own type parameters. For type parameter members, factory methods are generated instead of conversion operators (C# limitation). See diagnostics TTRESG071, TTRESG072, TTRESG107 for validation rules.
Copy file name to clipboardExpand all lines: src/Thinktecture.Runtime.Extensions.Analyzers/CodeAnalysis/Diagnostics/ThinktectureRuntimeExtensionsAnalyzer.cs
-14Lines changed: 0 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -23,7 +23,6 @@ public sealed class ThinktectureRuntimeExtensionsAnalyzer : DiagnosticAnalyzer
Copy file name to clipboardExpand all lines: src/Thinktecture.Runtime.Extensions.Roslyn.Sources/CodeAnalysis/DiagnosticsDescriptors.cs
+4-1Lines changed: 4 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -12,7 +12,6 @@ internal static class DiagnosticsDescriptors
12
12
publicstaticreadonlyDiagnosticDescriptorInnerSmartEnumOnFirstLevelMustBePrivate=new("TTRESG014","Inner Smart Enum on first level must be private","Derived inner Smart Enum '{0}' on first-level must be private",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
13
13
publicstaticreadonlyDiagnosticDescriptorInnerSmartEnumOnNonFirstLevelMustBePublic=new("TTRESG015","Inner Smart Enum on non-first level must be public","Derived inner Smart Enum '{0}' on non-first-level must be public",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
14
14
publicstaticreadonlyDiagnosticDescriptorKeyMemberShouldNotBeNullable=new("TTRESG017","The key member must not be nullable","A key member must not be nullable",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
15
-
publicstaticreadonlyDiagnosticDescriptorAdHocUnionsMustNotBeGeneric=new("TTRESG033","Ad hoc unions must not be generic","Type '{0}' must not be generic",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
16
15
publicstaticreadonlyDiagnosticDescriptorBaseClassFieldMustBeReadOnly=new("TTRESG034","Field of the base class must be read-only","The field '{0}' of the base class '{1}' must be read-only",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
17
16
publicstaticreadonlyDiagnosticDescriptorBaseClassPropertyMustBeReadOnly=new("TTRESG035","Property of the base class must be read-only","The property '{0}' of the base class '{1}' must be read-only",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
18
17
publicstaticreadonlyDiagnosticDescriptorSmartEnumKeyShouldNotBeNullable=new("TTRESG036","The key type must not be nullable","The generic type T of SmartEnumAttribute<T> must not be nullable",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
@@ -46,6 +45,9 @@ internal static class DiagnosticsDescriptors
46
45
publicstaticreadonlyDiagnosticDescriptorMultipleObjectFactoryAttributesWithUseWithEntityFramework=new("TTRESG068","Multiple ObjectFactoryAttribute instances cannot have UseWithEntityFramework = true","Type '{0}' has multiple ObjectFactoryAttribute instances with 'UseWithEntityFramework = true'. Only one ObjectFactoryAttribute can have 'UseWithEntityFramework = true'.",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
47
46
publicstaticreadonlyDiagnosticDescriptorMultipleObjectFactoryAttributesWithUseForModelBinding=new("TTRESG069","Multiple ObjectFactoryAttribute instances cannot have UseForModelBinding = true","Type '{0}' has multiple ObjectFactoryAttribute instances with 'UseForModelBinding = true'. Only one ObjectFactoryAttribute can have 'UseForModelBinding = true'.",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
48
47
publicstaticreadonlyDiagnosticDescriptorMultipleObjectFactoryAttributesWithOverlappingSerializationFrameworks=new("TTRESG070","Multiple ObjectFactoryAttribute instances cannot specify overlapping serialization frameworks","Type '{0}' has multiple ObjectFactoryAttribute instances with overlapping serialization frameworks '{1}'. Each serialization framework can only be used by one ObjectFactoryAttribute.",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
48
+
publicstaticreadonlyDiagnosticDescriptorTypeParamRefIndexOutOfRange=new("TTRESG071","TypeParamRef index exceeds the number of type parameters","TypeParamRef{0} references type parameter at index {0}, but the union type '{1}' has only {2} type parameter(s)",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
49
+
publicstaticreadonlyDiagnosticDescriptorTypeParamRefOnNonGenericUnion=new("TTRESG072","TypeParamRef cannot be used on non-generic ad-hoc union","TypeParamRef{0} cannot be used on non-generic ad-hoc union '{1}'",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
50
+
publicstaticreadonlyDiagnosticDescriptorAllowsRefStructNotSupportedOnAdHocUnion=new("TTRESG073","Ad-hoc unions do not support 'allows ref struct' type parameters","Ad-hoc union '{0}' has type parameter '{1}' with 'allows ref struct' which is not supported. Remove the 'allows ref struct' anti-constraint from the type parameter.",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
49
51
50
52
publicstaticreadonlyDiagnosticDescriptorErrorDuringModulesAnalysis=new("TTRESG097","Error during analysis of referenced modules","Error during analysis of referenced modules: '{0}'",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Error,true);
51
53
publicstaticreadonlyDiagnosticDescriptorErrorDuringCodeAnalysis=new("TTRESG098","Error during code analysis","Error during code analysis of '{0}': '{1}'",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Warning,true);
@@ -58,6 +60,7 @@ internal static class DiagnosticsDescriptors
58
60
publicstaticreadonlyDiagnosticDescriptorMembersDisallowingDefaultValuesMustBeRequired=new("TTRESG104","The member must be marked as 'required' to ensure proper initialization","The {0} '{1}' of type '{2}' must be marked as 'required' to ensure proper initialization",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Warning,true);
59
61
publicstaticreadonlyDiagnosticDescriptorComparisonAndEqualityOperatorsMismatch=new("TTRESG105","Comparison and equality operators settings mismatch","The type '{0}' has 'ComparisonOperators = {1}' and 'EqualityComparisonOperators = {2}' which differ. Set them to the same value.",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Warning,true);
60
62
publicstaticreadonlyDiagnosticDescriptorInnerTypeDoesNotDeriveFromUnion=new("TTRESG106","Inner type should derive from union type","The inner type '{0}' should derive from union type '{1}'",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Warning,true);
63
+
publicstaticreadonlyDiagnosticDescriptorGenericUnionWithoutTypeParamRef=new("TTRESG107","Generic ad-hoc union does not reference any type parameter via TypeParamRef","Generic ad-hoc union '{0}' does not reference any type parameter via TypeParamRef. All type parameters are unused.",Constants.ANALYZER_CATEGORY,DiagnosticSeverity.Warning,true);
61
64
62
65
publicstaticreadonlyDiagnosticDescriptorInternalApiUsage=new("TTRESG1000","Internal Thinktecture.Runtime.Extensions API usage","'{0}' is an internal API that supports the Thinktecture.Runtime.Extensions infrastructure and not subject to the same compatibility standards as public APIs. It may be changed or removed without notice in any release.",Constants.INTERNAL_USAGE_ANALYZER_CATEGORY,DiagnosticSeverity.Warning,true);
0 commit comments