Skip to content

feat: support abstract intermediate base classes in generator#4

Merged
ncipollina merged 3 commits intomainfrom
feat/abstract-base-class-support
Mar 31, 2026
Merged

feat: support abstract intermediate base classes in generator#4
ncipollina merged 3 commits intomainfrom
feat/abstract-base-class-support

Conversation

@ncipollina
Copy link
Copy Markdown
Contributor

Summary

Adds support for CRTP-style abstract base classes that sit between a concrete enum and OptimizedEnum<TEnum, TValue>. Previously, the abstract base class itself would be processed by the generator and emit a spurious OE0004 (no members found) diagnostic, blocking the pattern entirely.

Changes

src/LayeredCraft.OptimizedEnums.Generator/Providers/EnumSyntaxProvider.cs

  • Added if (classSymbol.IsAbstract) return null guard after the FindOptimizedEnumBase check — abstract classes are skipped silently, as they are intermediate base classes rather than concrete enums

tests/.../GeneratorVerifyTests.cs

  • AbstractBase_WithCRTP — verifies the CRTP pattern generates exactly one tree (for the concrete subclass) with no spurious diagnostics from the abstract base
  • AbstractBase_Alone_ProducesNoOutput — verifies a standalone abstract base produces zero output and zero diagnostics

Directory.Build.props — version bumped 1.1.01.1.1

Validation

  • All 42 tests pass across .NET 8, 9, and 10
  • New tests cover both the happy path and the abstract-base-in-isolation case

Release Notes

1.1.1 — Abstract intermediate base classes using the CRTP pattern are now silently skipped by the generator. Concrete subclasses continue to generate correctly with TEnum resolved to the concrete type.

// Now works without spurious OE0004
public abstract partial class DomainEnum<TSelf> : OptimizedEnum<TSelf, int>
    where TSelf : DomainEnum<TSelf>
{
    public string Description { get; }
    protected DomainEnum(int value, string name, string description)
        : base(value, name) { Description = description; }
}

public sealed partial class OrderStatus : DomainEnum<OrderStatus>
{
    public static readonly OrderStatus Pending = new(1, nameof(Pending), "Order is pending");
    private OrderStatus(int value, string name, string description)
        : base(value, name, description) { }
}

🤖 Generated with Claude Code

Skip abstract classes in EnumSyntaxProvider so that CRTP-style abstract
base classes (e.g. DomainEnum<TSelf> : OptimizedEnum<TSelf, int>) no
longer trigger spurious OE0004 diagnostics. Concrete subclasses are
still processed normally with TEnum correctly resolved to the concrete
type via the full inheritance chain walk.

Add two tests:
- AbstractBase_WithCRTP: verifies exactly one tree is generated for the
  concrete subclass with no diagnostics from the abstract base
- AbstractBase_Alone_ProducesNoOutput: verifies a standalone abstract
  base produces zero output and zero diagnostics

Bump version to 1.1.1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b6ce1618ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Abstract classes that declare members (e.g. abstract enums with
concrete nested implementations) should still generate normally.
The IsAbstract guard now lives inside the `validMembers.Count == 0`
block, so only memberless abstract base classes are skipped silently.

Adds AbstractEnum_WithMembers_StillGenerates regression test and
updates assertion messages for AbstractBase_Alone_ProducesNoOutput.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ncipollina
Copy link
Copy Markdown
Contributor Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eef4cb0e15

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- OE0101 (non-private constructor) is now suppressed for abstract
  classes since a protected constructor is idiomatic and required
  so concrete subclasses can invoke base(...)
- Abstract classes with no valid members but collected diagnostics
  (e.g. OE0102 on non-readonly fields) now return an EnumInfo so
  those diagnostics are reported; only truly clean abstract bases
  (no diagnostics) are silently skipped
- Removes the now-unnecessary DiagnosticsToSuppress for OE0101 in
  AbstractEnum_WithMembers_StillGenerates test
- Adds Warning_AbstractBase_WithOnlyInvalidMembers_StillSurfacesDiagnostics
  regression test verifying OE0102 is emitted for abstract types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ncipollina
Copy link
Copy Markdown
Contributor Author

@codex review

@ncipollina
Copy link
Copy Markdown
Contributor Author

@claude review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ncipollina ncipollina merged commit 0df79fe into main Mar 31, 2026
1 check passed
@ncipollina ncipollina deleted the feat/abstract-base-class-support branch March 31, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant