-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Extend Visitor generator to support interface and struct hierarchies #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Support interface-based hierarchies (e.g., IShape) - Support struct types that implement visitor interfaces - Intelligent visitor interface naming (IShape -> IShapeVisitor, not IIShapeVisitor) - Enhanced type discovery to find classes, structs, records, and interfaces - Add comprehensive tests for interface and struct hierarchies Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
- Add PKVIS001: Warning for no concrete types found - Add PKVIS002: Error for non-partial base types - Add PKVIS003: Warning for inaccessible types - Add PKVIS004: Error for non-partial derived types - Update AnalyzerReleases.Unshipped.md with new diagnostic IDs - Add IsPartial helper method for checking partial keyword Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
- Add comprehensive section on supported hierarchy types - Document interface-based hierarchies with examples - Document struct-based hierarchies for allocation-free patterns - Document record types support - Add Diagnostics section with all PKVIS001-004 errors - Update overview to mention support for all type kinds Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
- Add test for PKVIS001 (no concrete types found) - Add test for PKVIS002 (base type not partial) - Add test for PKVIS004 (derived type not partial) - Add test for valid hierarchy with no diagnostics - All 34 visitor generator tests passing Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
- Add using statement for Microsoft.CodeAnalysis.CSharp - Extract interface naming logic into GetDefaultVisitorInterfaceName method - Improve code maintainability and testability - All tests passing, CodeQL clean Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Test Results145 tests 145 ✅ 25s ⏱️ Results for commit eb05aaa. ♻️ This comment has been updated with latest results. |
🔍 PR Validation ResultsVersion: `` ✅ Validation Steps
📊 ArtifactsDry-run artifacts have been uploaded and will be available for 7 days. This comment was automatically generated by the PR validation workflow. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #90 +/- ##
==========================================
+ Coverage 85.75% 90.09% +4.33%
==========================================
Files 143 143
Lines 12205 12288 +83
Branches 1623 1641 +18
==========================================
+ Hits 10467 11071 +604
+ Misses 1329 1217 -112
+ Partials 409 0 -409
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request extends the Visitor Pattern Generator to support interface, struct, and record hierarchies, not just class-based hierarchies. The generator now produces visitor infrastructure for any type hierarchy marked with [GenerateVisitor], enabling value-type visitors without boxing and interface-based polymorphism patterns.
Changes:
- Extended type discovery to accept interfaces, structs, and records as base types for visitor hierarchies
- Implemented intelligent visitor interface naming that avoids double-I prefixes for interface base types (IShape → IShapeVisitor)
- Added four new diagnostics (PKVIS001-004) to validate hierarchy structure and partial keyword requirements
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/PatternKit.Generators/VisitorGenerator.cs | Core generator logic extended with interface/struct support, type discovery helpers, and diagnostic reporting |
| test/PatternKit.Generators.Tests/VisitorGeneratorTests.cs | Added 6 new tests covering interface/struct hierarchies and diagnostic validation |
| src/PatternKit.Generators.Abstractions/Visitors/VisitorAttributes.cs | Updated AttributeUsage to allow Interface and Struct targets |
| docs/generators/visitor-generator.md | Comprehensive documentation of new hierarchy types and diagnostic codes |
| src/PatternKit.Generators/AnalyzerReleases.Unshipped.md | Documented four new diagnostic codes |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot apply changes based on the comments in this thread |
- Remove interface exclusion from partial check (fixes PKVIS002 for interfaces) - Add proper record type keyword detection (record/record struct) - Remove unused PKVIS003 diagnostic - Add explicit .Where() and .Select() for better readability - Simplify IsPartial method with LINQ - Add tests for record hierarchies - Add test for non-partial interface base types - Update documentation to remove PKVIS003 All 37 tests passing. Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
All review feedback addressed in commit 99942b4. Changes include: ✅ Fixed interface partial validation (PKVIS002 now applies to interfaces) All 37 tests passing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot apply changes based on the comments in this thread |
- Use IsDerivedFrom instead of ImplementsInterface for struct discovery (consistency) - Update documentation to clarify interfaces also require partial keyword - All 37 tests passing Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Both issues addressed in commit eb05aaa: ✅ Structs now use All 37 tests passing. |
Code Coverage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (type.IsRecord) | ||
| { | ||
| typeKeyword = type.TypeKind == TypeKind.Struct | ||
| ? "record struct" | ||
| : "record"; | ||
| } | ||
| else | ||
| { | ||
| typeKeyword = type.TypeKind switch | ||
| { | ||
| TypeKind.Interface => "interface", | ||
| TypeKind.Struct => "struct", | ||
| _ => "class" | ||
| }; | ||
| } |
Copilot
AI
Jan 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.
Visitor Pattern Generator Enhancement Plan
Analysis Complete
Implementation Plan
Phase 1: Core Enhancements
Phase 2: Advanced Features
Phase 3: Documentation & Testing
Phase 4: Quality & Coverage
Completed Features
PR Review Feedback Addressed
First Review (99942b4):
Second Review (this commit):
Original prompt
This section details on the original issue you should resolve
<issue_title>Generator: Create Visitor Pattern</issue_title>
<issue_description>## Summary
Implement a source generator that emits all the boilerplate normally required for the Visitor design pattern, including:
All generated code should be:
Motivation & Context
The Visitor pattern is a classic behavioral design pattern that separates algorithms from the objects on which they operate, enabling new operations to be added without modifying the object structure. ([refactoring.guru][2])
In C#, implementing a visitor typically requires:
Visitmethod for each concrete elementAcceptmethod in every elementSource generation can make this automatic, safe, and ergonomic.
Goals
G1 — Source-gen visitor interfaces and accept methods
From minimal input, generate a visitor interface (or interfaces) and implement the required accept methods on all participating types.
G2 — Support multiple visitor families
Allow multiple independent visitor sets within a single project.
For example, one family for validation logic and another for serialization logic.
G3 — Support void and generic visitors
Visitor operations should optionally return values (
TResult) and accept context parameters.G4 — Make the generated API ergonomic
Prefer compile-time dispatch over
switch/if/ type casting. Avoid reflection entirely.G5 — Deterministic ordering & diagnostics
The generator should provide diagnostics if new concrete types are introduced but not included in visitors, and deterministic visit order where applicable.
User Experience
Opt-in Model
Users mark a base type and, optionally, concrete types they want included in a visitor family.
Example: Interface base
User defines shapes:
The generator produces:
IShapeVisitorinterface withVisit(Circle),Visit(Rectangle),Visit(Triangle)Accept(visitor)on each concrete typeExample: Abstract base class
User defines:
Generated code augments both with
Accept.Generated Output (Desired Shape)
Visitor Interface
Generated on the base type:
Generic Visitor
Optionally support returning a result:
Accept Methods
Multiple Visitor Families Supported
Example with diagnostics:
Each family emits:
IAstNodeVisitor_ValidationIAstNodeVisitor_RenderingOptions & Extensions
Support for Interface Segregation
Allow optional base visitor interfaces to group common visit methods:
Generated visitors implement the base.
Context Parameters
Visitors may accept a context parameter:
This allows stateful visitors without external state capture.
Default Implementation Hooks
Generated partial visitor interface stub could contain no-op defaults:
Optional generator flag to emit defaults.
Diagnostics
Provide generator diagnostics for:
| ID | Meaning |
| -------- | -------------------...
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.