Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 22, 2026

Decorator Pattern Source Generator - PR Review Round 3 ✅

✅ All PR Review Comments Addressed (8/8)

1. Static Members Handling

  • ✅ Static methods and properties now filtered out (ignored silently)
  • ✅ Decorators only forward instance members
  • ✅ Added test for static member filtering

2. Generic Methods

  • ✅ Added PKDEC002 diagnostic for generic methods (not supported in v1)
  • ✅ Added test for generic method diagnostic

3. Property Accessor Accessibility

  • ✅ Now checks accessor-level accessibility (get/set)
  • ✅ Properties with inaccessible accessors emit PKDEC004
  • ✅ Handles public get; protected set; scenarios
  • ✅ Added test for protected setter diagnostic

4. Fields & Nested Types

  • ✅ Only report PKDEC002 for accessible fields/nested types
  • ✅ Private implementation details now silently ignored
  • ✅ Prevents spurious errors on abstract classes with private fields

5. PKDEC004 Message

  • ✅ Updated to accurately describe supported accessibilities
  • ✅ Clarifies pure protected members not accessible through Inner

6. DecoratorIgnoreAttribute Documentation

  • ✅ Updated to reflect sealed override behavior for abstract classes
  • ✅ Clarifies it doesn't strip override for abstract/virtual contracts

7. Code Style

  • ✅ Simplified if/else to ternary operators (2 locations)

📊 Test Results

  • Tests: 24/24 decorator tests passing (100%)
  • Added: 3 new tests (generic method, static members, protected setter)
  • Total: 169/169 all tests passing

🔧 Key Improvements

  1. Better Error Messages: PKDEC004 now clearly explains accessibility rules
  2. Fewer False Positives: Private fields/nested types no longer trigger errors
  3. Static Member Support: Static members properly ignored
  4. Generic Method Detection: Clear diagnostic when using unsupported generic methods
  5. Accessor-Level Validation: Catches protected set and similar scenarios

Production ready with enhanced edge case handling!

Original prompt

This section details on the original issue you should resolve

<issue_title>Generator: Create Decorator Pattern</issue_title>
<issue_description>## Summary

Add a source generator that produces boilerplate-free, GoF-consistent Decorator pattern implementations for interfaces and abstract classes.

The generator lives in PatternKit.Generators and emits self-contained, readable C# with no runtime PatternKit dependency.

Primary goals:

  • Generate typed decorators without reflection.
  • Make ordering explicit and deterministic.
  • Support both “wrapper class” style and “pipeline” (next) style.
  • Support sync + async members (favor ValueTask for generated hooks).

Motivation / Problem

Decorator chains are frequently hand-written and drift:

  • missing forwarding members
  • inconsistent ordering semantics
  • repeated logging/timing/retry boilerplate
  • async gets messy quickly

Source generation can emit correct forwarding + consistent hooks once.


Supported Targets (must-have)

Decorator generation must support:

  • interface
  • abstract class (virtual/abstract members only)

Decorator generation is opt-in via attribute on the contract.


Proposed User Experience

A) Generate base decorator + optional pipeline builder

[GenerateDecorator]
public partial interface IStorage
{
    Stream OpenRead(string path);
    ValueTask<Stream> OpenReadAsync(string path, CancellationToken ct = default);
}

Generated (representative shape):

public abstract partial class StorageDecoratorBase : IStorage
{
    protected StorageDecoratorBase(IStorage inner);

    protected IStorage Inner { get; }

    public virtual Stream OpenRead(string path) => Inner.OpenRead(path);
    public virtual ValueTask<Stream> OpenReadAsync(string path, CancellationToken ct = default)
        => Inner.OpenReadAsync(path, ct);
}

public static partial class StorageDecorators
{
    public static IStorage Compose(IStorage inner, params Func<IStorage, IStorage>[] decorators);
}

B) Typed decorators written by users

public sealed class CachingStorage : StorageDecoratorBase
{
    public CachingStorage(IStorage inner) : base(inner) { }

    public override Stream OpenRead(string path) { /* cache */ }
}

The generator ensures the base class always stays in sync with the contract.


Attributes / Surface Area

Namespace: PatternKit.Generators.Decorator

  • [GenerateDecorator] on contract type

    • string? BaseTypeName (default: <ContractName>DecoratorBase)
    • string? HelpersTypeName (default: <ContractName>Decorators)
    • DecoratorCompositionMode Composition (default: HelpersOnly)
    • bool GenerateAsync (default: inferred)
    • bool ForceAsync (default: false)

Optional:

  • [DecoratorIgnore] for members to exclude.

Enums:

  • DecoratorCompositionMode: None, HelpersOnly, PipelineNextStyle (v2)

Semantics (must-have)

Forwarding correctness

  • Base decorator forwards all included members to Inner.
  • For abstract class contracts, only virtual/abstract members are forwarded.

Composition helper ordering

If helper Compose is generated:

  • decorators applied in array order.

  • ordering must be documented:

    • decorators[0] is outermost by default.

Async

  • Base decorator preserves exact signature from contract.
  • No signature rewriting.

Diagnostics (must-have)

  • PKDEC001 Type marked [GenerateDecorator] must be partial.
  • PKDEC002 Unsupported member kind (e.g., event) for v1.
  • PKDEC003 Name conflict for generated base/helper types.
  • PKDEC004 Member not accessible for generation.

Generated Code Layout

  • ContractName.Decorator.g.cs

Determinism:

  • stable emission order by fully-qualified member name.

Testing Expectations

  • Base decorator forwards calls correctly.
  • Composition helper wraps in deterministic order.
  • Async forwarding works.
  • Diagnostics: unsupported members, naming conflicts.

Acceptance Criteria

  • [GenerateDecorator] works for interfaces and abstract classes.
  • Generated base decorator forwards all members correctly.
  • Optional composition helpers generated with deterministic ordering.
  • Async members supported without signature rewriting.
  • Diagnostics and tests included.
    </issue_description>

<agent_instructions>Ensure complete BDD code coverage, comprehensive realworld usage examples and demos, user guides, and congruence with our existing implementations.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 4 commits January 22, 2026 05:42
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Copilot AI changed the title [WIP] Add source generator for decorator pattern implementations feat: Add Decorator pattern source generator Jan 22, 2026
Copilot AI requested a review from JerrettDavis January 22, 2026 06:17
@JerrettDavis JerrettDavis marked this pull request as ready for review January 22, 2026 06:35
@JerrettDavis JerrettDavis requested a review from Copilot January 22, 2026 06:35
@github-actions
Copy link
Contributor

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions
Copy link
Contributor

Test Results

158 tests   158 ✅  56s ⏱️
  1 suites    0 💤
  1 files      0 ❌

Results for commit 7047b99.

@github-actions
Copy link
Contributor

Code Coverage

Summary
  Generated on: 01/22/2026 - 06:38:32
  Coverage date: 01/22/2026 - 06:37:47 - 01/22/2026 - 06:38:26
  Parser: MultiReport (9x Cobertura)
  Assemblies: 4
  Classes: 347
  Files: 215
  Line coverage: 79.6%
  Covered lines: 11458
  Uncovered lines: 2922
  Coverable lines: 14380
  Total lines: 37240
  Branch coverage: 71% (3450 of 4853)
  Covered branches: 3450
  Total branches: 4853
  Method coverage: 76.5% (2281 of 2981)
  Full method coverage: 71% (2118 of 2981)
  Covered methods: 2281
  Fully covered methods: 2118
  Total methods: 2981

PatternKit.Core                                                                                                   96.8%
  PatternKit.Behavioral.Chain.ActionChain<T>                                                                       100%
  PatternKit.Behavioral.Chain.AsyncActionChain<T>                                                                  100%
  PatternKit.Behavioral.Chain.AsyncResultChain<T1, T2>                                                            97.7%
  PatternKit.Behavioral.Chain.ResultChain<T1, T2>                                                                  100%
  PatternKit.Behavioral.Command.Command<T>                                                                         100%
  PatternKit.Behavioral.Interpreter.ActionInterpreter                                                              100%
  PatternKit.Behavioral.Interpreter.ActionInterpreter<T>                                                          96.9%
  PatternKit.Behavioral.Interpreter.ActionInterpreterBuilder<T>                                                    100%
  PatternKit.Behavioral.Interpreter.AsyncActionInterpreter                                                         100%
  PatternKit.Behavioral.Interpreter.AsyncActionInterpreter<T>                                                      100%
  PatternKit.Behavioral.Interpreter.AsyncActionInterpreterBuilder<T>                                               100%
  PatternKit.Behavioral.Interpreter.AsyncInterpreter                                                               100%
  PatternKit.Behavioral.Interpreter.AsyncInterpreter<T1, T2>                                                      96.8%
  PatternKit.Behavioral.Interpreter.AsyncInterpreterBuilder<T1, T2>                                                100%
  PatternKit.Behavioral.Interpreter.Builder<T1, T2>                                                                 96%
  PatternKit.Behavioral.Interpreter.ExpressionExtensions                                                           100%
  PatternKit.Behavioral.Interpreter.Interpreter                                                                    100%
  PatternKit.Behavioral.Interpreter.Interpreter<T1, T2>                                                           96.6%
  PatternKit.Behavioral.Interpreter.NonTerminalExpression                                                          100%
  PatternKit.Behavioral.Interpreter.TerminalExpression                                                             100%
  PatternKit.Behavioral.Iterator.AsyncFlow<T>                                                                      100%
  PatternKit.Behavioral.Iterator.AsyncFlowExtensions                                                               100%
  PatternKit.Behavioral.Iterator.AsyncReplayBuffer<T>                                                             93.6%
  PatternKit.Behavioral.Iterator.Flow<T>                                                                          94.4%
  PatternKit.Behavioral.Iterator.FlowExtensions                                                                    100%
  PatternKit.Behavioral.Iterator.ReplayableSequence<T>                                                            98.2%
  PatternKit.Behavioral.Iterator.ReplayableSequenceExtensions                                                      100%
  PatternKit.Behavioral.Iterator.SharedAsyncFlow<T>                                                                100%
  PatternKit.Behavioral.Iterator.SharedFlow<T>                                                                     100%
  PatternKit.Behavioral.Iterator.WindowSequence                                                                    100%
  PatternKit.Behavioral.Mediator.Mediator                                                                         91.9%
  PatternKit.Behavioral.Mediator.MediatorHelpers                                                                   100%
  PatternKit.Behavioral.Mediator.TaskExtensions                                                                    100%
  PatternKit.Behavioral.Memento.Memento<T>                                                                         100%
  PatternKit.Behavioral.Observer.AsyncObserver<T>                                                                 98.7%
  PatternKit.Behavioral.Observer.Observer<T>                                                                      98.2%
  PatternKit.Behavioral.State.AsyncStateMachine<T1, T2>                                                             95%
  PatternKit.Behavioral.State.StateMachine<T1, T2>                                                                  99%
  PatternKit.Behavioral.Strategy.ActionStrategy<T>                                                                  97%
  PatternKit.Behavioral.Strategy.AsyncActionStrategy<T>                                                            100%
  PatternKit.Behavioral.Strategy.AsyncStrategy<T1, T2>                                                             100%
  PatternKit.Behavioral.Strategy.Strategy<T1, T2>                                                                  100%
  PatternKit.Behavioral.Strategy.TryStrategy<T1, T2>                                                              95.8%
  PatternKit.Behavioral.Template.ActionTemplate<T>                                                                 100%
  PatternKit.Behavioral.Template.AsyncActionTemplate<T>                                                            100%
  PatternKit.Behavioral.Template.AsyncTemplate<T1, T2>                                                            97.1%
  PatternKit.Behavioral.Template.AsyncTemplateMethod<T1, T2>                                                       100%
  PatternKit.Behavioral.Template.Template<T1, T2>                                                                  100%
  PatternKit.Behavioral.Template.TemplateMethod<T1, T2>                                                            100%
  PatternKit.Behavioral.TypeDispatcher.ActionTypeDispatcher<T>                                                    91.4%
  PatternKit.Behavioral.TypeDispatcher.AsyncActionTypeDispatcher<T>                                               94.5%
  PatternKit.Behavioral.TypeDispatcher.AsyncTypeDispatcher<T1, T2>                                                94.4%
  PatternKit.Behavioral.TypeDispatcher.TypeDispatcher<T1, T2>                                                      100%
  PatternKit.Behavioral.Visitor.ActionVisitor<T>                                                                  85.7%
  PatternKit.Behavioral.Visitor.ActionVisitorBase<T>                                                               100%
  PatternKit.Behavioral.Visitor.AsyncActionVisitor<T>                                                             94.5%
  PatternKit.Behavioral.Visitor.AsyncFluentActionVisitor<T>                                                        100%
  PatternKit.Behavioral.Visitor.AsyncFluentVisitor<T1, T2>                                                         100%
  PatternKit.Behavioral.Visitor.AsyncVisitor<T1, T2>                                                              86.1%
  PatternKit.Behavioral.Visitor.FluentActionVisitor<T>                                                             100%
  PatternKit.Behavioral.Visitor.FluentVisitor<T1, T2>                                                              100%
  PatternKit.Behavioral.Visitor.Visitor<T1, T2>                                                                   91.1%
  PatternKit.Behavioral.Visitor.VisitorBase<T1, T2>                                                                100%
  PatternKit.Common.Option<T>                                                                                      100%
  PatternKit.Common.Throw                                                                                          100%
  PatternKit.Common.TryHandlerExtensions                                                                           100%
  PatternKit.Creational.AbstractFactory.AbstractFactory<T>                                                        91.6%
  PatternKit.Creational.Builder.BranchBuilder<T1, T2>                                                              100%
  PatternKit.Creational.Builder.BuilderExtensions                                                                  100%
  PatternKit.Creational.Builder.ChainBuilder<T>                                                                    100%
  PatternKit.Creational.Builder.Composer<T1, T2>                                                                   100%
  PatternKit.Creational.Builder.MutableBuilder<T>                                                                  100%
  PatternKit.Creational.Factory.Factory<T1, T2>                                                                   92.3%
  PatternKit.Creational.Factory.Factory<T1, T2, T3>                                                               92.3%
  PatternKit.Creational.Prototype.Prototype<T>                                                                     100%
  PatternKit.Creational.Prototype.Prototype<T1, T2>                                                                 90%
  PatternKit.Creational.Singleton.Singleton<T>                                                                    96.5%
  PatternKit.Structural.Adapter.Adapter<T1, T2>                                                                    100%
  PatternKit.Structural.Adapter.AsyncAdapter<T1, T2>                                                               100%
  PatternKit.Structural.Bridge.ActionBridge<T1, T2>                                                               90.9%
  PatternKit.Structural.Bridge.AsyncActionBridge<T1, T2>                                                          96.5%
  PatternKit.Structural.Bridge.AsyncBridge<T1, T2, T3>                                                            90.6%
  PatternKit.Structural.Bridge.Bridge<T1, T2, T3>                                                                  100%
  PatternKit.Structural.Composite.ActionComposite<T>                                                               100%
  PatternKit.Structural.Composite.AsyncActionComposite<T>                                                          100%
  PatternKit.Structural.Composite.AsyncComposite<T1, T2>                                                          97.8%
  PatternKit.Structural.Composite.Composite<T1, T2>                                                               97.3%
  PatternKit.Structural.Decorator.ActionDecorator<T>                                                               100%
  PatternKit.Structural.Decorator.AsyncActionDecorator<T>                                                          100%
  PatternKit.Structural.Decorator.AsyncDecorator<T1, T2>                                                            98%
  PatternKit.Structural.Decorator.Decorator<T1, T2>                                                               97.6%
  PatternKit.Structural.Facade.Facade<T1, T2>                                                                     88.8%
  PatternKit.Structural.Facade.TypedFacade<T>                                                                     79.4%
  PatternKit.Structural.Facade.TypedFacadeDispatchProxy<T>                                                        81.8%
  PatternKit.Structural.Facade.TypedFacadeProxyFactory<T>                                                          100%
  PatternKit.Structural.Flyweight.Flyweight<T1, T2>                                                                100%
  PatternKit.Structural.Proxy.ActionProxy<T>                                                                       100%
  PatternKit.Structural.Proxy.AsyncActionProxy<T>                                                                  100%
  PatternKit.Structural.Proxy.AsyncProxy<T1, T2>                                                                  98.6%
  PatternKit.Structural.Proxy.Proxy<T1, T2>                                                                       98.8%

PatternKit.Examples                                                                                               63.6%
  PatternKit.Examples.AbstractFactoryDemo.AbstractFactoryDemo                                                     98.2%
  PatternKit.Examples.ApiGateway.Demo                                                                             97.9%
  PatternKit.Examples.ApiGateway.MiniRouter                                                                       96.6%
  PatternKit.Examples.ApiGateway.Request                                                                            75%
  PatternKit.Examples.ApiGateway.Response                                                                          100%
  PatternKit.Examples.ApiGateway.Responses                                                                         100%
  PatternKit.Examples.AsyncStateDemo.ConnectionStateDemo                                                          93.5%
  PatternKit.Examples.BridgeDemo.BridgeDemo                                                                       96.7%
  PatternKit.Examples.Chain.AuthLoggingDemo                                                                       95.2%
  PatternKit.Examples.Chain.CardProcessors                                                                         100%
  PatternKit.Examples.Chain.CardTenderStrategy                                                                    77.7%
  PatternKit.Examples.Chain.CashTenderStrategy                                                                     100%
  PatternKit.Examples.Chain.ChainStage                                                                             100%
  PatternKit.Examples.Chain.CharityRoundUpRule                                                                      50%
  PatternKit.Examples.Chain.ConfigDriven.Bundle1OffEach                                                           14.2%
  PatternKit.Examples.Chain.ConfigDriven.CardTender                                                               72.2%
  PatternKit.Examples.Chain.ConfigDriven.Cash2Pct                                                                 16.6%
  PatternKit.Examples.Chain.ConfigDriven.CashTender                                                               90.9%
  PatternKit.Examples.Chain.ConfigDriven.CharityRoundUp                                                            100%
  PatternKit.Examples.Chain.ConfigDriven.ConfigDrivenPipelineBuilderExtensions                                    94.2%
  PatternKit.Examples.Chain.ConfigDriven.ConfigDrivenPipelineDemo                                                  100%
  PatternKit.Examples.Chain.ConfigDriven.Loyalty5Pct                                                                20%
  PatternKit.Examples.Chain.ConfigDriven.NickelCashOnly                                                           77.7%
  PatternKit.Examples.Chain.ConfigDriven.PipelineOptions                                                           100%
  PatternKit.Examples.Chain.Customer                                                                               100%
  PatternKit.Examples.Chain.DeviceBus                                                                              100%
  PatternKit.Examples.Chain.GenericProcessor                                                                       100%
  PatternKit.Examples.Chain.HttpRequest                                                                            100%
  PatternKit.Examples.Chain.IRoundingRule                                                                          100%
  PatternKit.Examples.Chain.LineItem                                                                               100%
  PatternKit.Examples.Chain.MediatedTransactionPipelineDemo                                                        100%
  PatternKit.Examples.Chain.NickelCashOnlyRule                                                                     100%
  PatternKit.Examples.Chain.NoopCharityTracker                                                                     100%
  PatternKit.Examples.Chain.RoundingPipeline                                                                       100%
  PatternKit.Examples.Chain.Tender                                                                                 100%
  PatternKit.Examples.Chain.TenderRouterFactory                                                                   91.3%
  PatternKit.Examples.Chain.TransactionContext                                                                     100%
  PatternKit.Examples.Chain.TransactionPipeline                                                                    100%
  PatternKit.Examples.Chain.TransactionPipelineBuilder                                                            92.3%
  PatternKit.Examples.Chain.TxResult                                                                               100%
  PatternKit.Examples.CompositeDemo.CompositeDemo                                                                  100%
  PatternKit.Examples.Decorators.CachingFileStorage                                                                  0%
  PatternKit.Examples.Decorators.FileStorageDecoratorBase                                                            0%
  PatternKit.Examples.Decorators.FileStorageDecorators                                                               0%
  PatternKit.Examples.Decorators.InMemoryFileStorage                                                                 0%
  PatternKit.Examples.Decorators.LoggingFileStorage                                                                  0%
  PatternKit.Examples.Decorators.RetryFileStorage                                                                    0%
  PatternKit.Examples.Decorators.StorageDecoratorDemo                                                                0%
  PatternKit.Examples.EnterpriseDemo.EnterpriseOrderDemo                                                          97.1%
  PatternKit.Examples.FacadeDemo.FacadeDemo                                                                        100%
  PatternKit.Examples.FlyweightDemo.FlyweightDemo                                                                 96.9%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.BackgroundJobsModule                     100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApp                             100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplication                    21.4%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplicationBuilder             52.6%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplicationBuilderExtensions   94.7%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplicationDemo                27.2%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateAppState                        100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.InMemoryJobScheduler                     100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.MessagingModule                          100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.NotificationOptions                        0%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.ObservabilityModule                      100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.QueueNotificationPublisher               100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.SecretsProvider                          100%
  PatternKit.Examples.Generators.Factories.ApplicationOrchestrator                                                   0%
  PatternKit.Examples.Generators.Factories.BackgroundWorker                                                        100%
  PatternKit.Examples.Generators.Factories.ConsoleMetricsSink                                                      100%
  PatternKit.Examples.Generators.Factories.MemoryCacheProvider                                                     100%
  PatternKit.Examples.Generators.Factories.OrchestratorStepFactory                                                13.4%
  PatternKit.Examples.Generators.Factories.SeedDataStep                                                            100%
  PatternKit.Examples.Generators.Factories.ServiceModuleBootstrap                                                  100%
  PatternKit.Examples.Generators.Factories.ServiceModules                                                           44%
  PatternKit.Examples.Generators.Factories.StartWorkersStep                                                        100%
  PatternKit.Examples.Generators.Factories.WarmCacheStep                                                           100%
  PatternKit.Examples.Generators.Memento.EditorStateDemo                                                             0%
  PatternKit.Examples.Generators.Memento.EditorStateHistory                                                          0%
  PatternKit.Examples.Generators.Memento.EditorStateMemento                                                          0%
  PatternKit.Examples.Generators.Memento.GameStateDemo                                                               0%
  PatternKit.Examples.Generators.Memento.GameStateHistory                                                            0%
  PatternKit.Examples.Generators.Memento.GameStateMemento                                                            0%
  PatternKit.Examples.Generators.Strategies.IntParser                                                               60%
  PatternKit.Examples.Generators.Strategies.OrderRouter                                                           95.2%
  PatternKit.Examples.Generators.Strategies.ScoreLabeler                                                           100%
  PatternKit.Examples.Generators.Visitors.Document                                                                   0%
  PatternKit.Examples.Generators.Visitors.DocumentActionVisitorBuilder                                               0%
  PatternKit.Examples.Generators.Visitors.DocumentAsyncActionVisitorBuilder                                          0%
  PatternKit.Examples.Generators.Visitors.DocumentAsyncVisitorBuilder<T>                                             0%
  PatternKit.Examples.Generators.Visitors.DocumentProcessingDemo                                                     0%
  PatternKit.Examples.Generators.Visitors.DocumentVisitorBuilder<T>                                                  0%
  PatternKit.Examples.Generators.Visitors.MarkdownDocument                                                           0%
  PatternKit.Examples.Generators.Visitors.PdfDocument                                                                0%
  PatternKit.Examples.Generators.Visitors.SpreadsheetDocument                                                        0%
  PatternKit.Examples.Generators.Visitors.WordDocument                                                               0%
  PatternKit.Examples.InterpreterDemo.InterpreterDemo                                                             93.1%
  PatternKit.Examples.IteratorDemo.IteratorDemo                                                                   98.8%
  PatternKit.Examples.MediatorDemo.AppMediator                                                                     100%
  PatternKit.Examples.MediatorDemo.AuditLogHandler                                                                 100%
  PatternKit.Examples.MediatorDemo.BoxHelper                                                                        25%
  PatternKit.Examples.MediatorDemo.CountUpCmd                                                                      100%
  PatternKit.Examples.MediatorDemo.CountUpHandler                                                                  100%
  PatternKit.Examples.MediatorDemo.EchoCmd                                                                         100%
  PatternKit.Examples.MediatorDemo.EchoHandler                                                                     100%
  PatternKit.Examples.MediatorDemo.LoggingBehavior<T1, T2>                                                         100%
  PatternKit.Examples.MediatorDemo.MediatorAssemblyScanner                                                         100%
  PatternKit.Examples.MediatorDemo.MediatorDemoSink                                                                100%
  PatternKit.Examples.MediatorDemo.MediatorRegistry                                                                100%
  PatternKit.Examples.MediatorDemo.PingCmd                                                                         100%
  PatternKit.Examples.MediatorDemo.PingHandler                                                                     100%
  PatternKit.Examples.MediatorDemo.ServiceCollectionExtensions                                                    83.3%
  PatternKit.Examples.MediatorDemo.SumCmd                                                                          100%
  PatternKit.Examples.MediatorDemo.SumCmdBehavior                                                                  100%
  PatternKit.Examples.MediatorDemo.SumHandler                                                                      100%
  PatternKit.Examples.MediatorDemo.UserCreated                                                                     100%
  PatternKit.Examples.MediatorDemo.WelcomeEmailHandler                                                             100%
  PatternKit.Examples.MementoDemo.MementoDemo                                                                     83.5%
  PatternKit.Examples.Messaging.CreateUser                                                                           0%
  PatternKit.Examples.Messaging.DispatcherUsageExamples                                                              0%
  PatternKit.Examples.Messaging.EmailSent                                                                            0%
  PatternKit.Examples.Messaging.OrderPlaced                                                                          0%
  PatternKit.Examples.Messaging.PagedItem                                                                            0%
  PatternKit.Examples.Messaging.PagedRequest                                                                         0%
  PatternKit.Examples.Messaging.SearchQuery                                                                          0%
  PatternKit.Examples.Messaging.SearchResult                                                                         0%
  PatternKit.Examples.Messaging.SendEmail                                                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.ComprehensiveMediatorDemo                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.CreateCustomerCommand                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.CreateCustomerHandler                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.Customer                                                             0%
  PatternKit.Examples.Messaging.SourceGenerated.CustomerCreatedEvent                                                 0%
  PatternKit.Examples.Messaging.SourceGenerated.GetCustomerHandler                                                   0%
  PatternKit.Examples.Messaging.SourceGenerated.GetCustomerQuery                                                     0%
  PatternKit.Examples.Messaging.SourceGenerated.GetOrdersByCustomerHandler                                           0%
  PatternKit.Examples.Messaging.SourceGenerated.GetOrdersByCustomerQuery                                             0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryCustomerRepository                                           0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryLogger                                                       0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryOrderRepository                                              0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryProductRepository                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.LoggingBehavior<T1, T2>                                              0%
  PatternKit.Examples.Messaging.SourceGenerated.MediatorServiceCollectionExtensions                                  0%
  PatternKit.Examples.Messaging.SourceGenerated.NotifyInventoryHandler                                               0%
  PatternKit.Examples.Messaging.SourceGenerated.Order                                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.OrderItem                                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.OrderPlacedEvent                                                     0%
  PatternKit.Examples.Messaging.SourceGenerated.PaymentProcessedEvent                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.PerformanceBehavior<T1, T2>                                          0%
  PatternKit.Examples.Messaging.SourceGenerated.PlaceOrderCommand                                                    0%
  PatternKit.Examples.Messaging.SourceGenerated.PlaceOrderHandler                                                    0%
  PatternKit.Examples.Messaging.SourceGenerated.ProcessPaymentCommand                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.ProcessPaymentHandler                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.ProductionDispatcher                                                 0%
  PatternKit.Examples.Messaging.SourceGenerated.ProductSearchResult                                                  0%
  PatternKit.Examples.Messaging.SourceGenerated.RecordPaymentAuditHandler                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.SearchProductsHandler                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.SearchProductsQuery                                                  0%
  PatternKit.Examples.Messaging.SourceGenerated.SendOrderConfirmationHandler                                         0%
  PatternKit.Examples.Messaging.SourceGenerated.SendWelcomeEmailHandler                                              0%
  PatternKit.Examples.Messaging.SourceGenerated.TransactionBehavior<T1, T2>                                          0%
  PatternKit.Examples.Messaging.SourceGenerated.UpdateCustomerStatsHandler                                           0%
  PatternKit.Examples.Messaging.SourceGenerated.ValidationBehavior<T1, T2>                                           0%
  PatternKit.Examples.Messaging.UserCreated                                                                          0%
  PatternKit.Examples.Messaging.UserRegistered                                                                       0%
  PatternKit.Examples.ObserverDemo.EventHub<T>                                                                     100%
  PatternKit.Examples.ObserverDemo.LineItem                                                                        100%
  PatternKit.Examples.ObserverDemo.ObservableList<T>                                                                47%
  PatternKit.Examples.ObserverDemo.ObservableVar<T>                                                                100%
  PatternKit.Examples.ObserverDemo.ProfileViewModel                                                                100%
  PatternKit.Examples.ObserverDemo.PropertyChangedHub                                                              100%
  PatternKit.Examples.ObserverDemo.ReactiveTransaction                                                            95.4%
  PatternKit.Examples.ObserverDemo.UserEvent                                                                       100%
  PatternKit.Examples.PatternShowcase.PatternShowcase                                                             91.2%
  PatternKit.Examples.PointOfSale.CustomerInfo                                                                     100%
  PatternKit.Examples.PointOfSale.Demo                                                                            99.6%
  PatternKit.Examples.PointOfSale.OrderLineItem                                                                    100%
  PatternKit.Examples.PointOfSale.PaymentProcessorDemo                                                            95.7%
  PatternKit.Examples.PointOfSale.PaymentReceipt                                                                   100%
  PatternKit.Examples.PointOfSale.PromotionConfig                                                                  100%
  PatternKit.Examples.PointOfSale.PurchaseOrder                                                                    100%
  PatternKit.Examples.PointOfSale.ReceiptLineItem                                                                  100%
  PatternKit.Examples.PointOfSale.StoreLocation                                                                    100%
  PatternKit.Examples.Pricing.ApiPricingSource                                                                     100%
  PatternKit.Examples.Pricing.CharityRoundUpRule                                                                   100%
  PatternKit.Examples.Pricing.Coupon                                                                               100%
  PatternKit.Examples.Pricing.DbPricingSource                                                                      100%
  PatternKit.Examples.Pricing.DefaultSourceRouting                                                                83.3%
  PatternKit.Examples.Pricing.FilePricingSource                                                                    100%
  PatternKit.Examples.Pricing.LineItem                                                                             100%
  PatternKit.Examples.Pricing.Location                                                                             100%
  PatternKit.Examples.Pricing.LoyaltyMembership                                                                    100%
  PatternKit.Examples.Pricing.NickelCashOnlyRule                                                                   100%
  PatternKit.Examples.Pricing.PercentLoyaltyRule                                                                   100%
  PatternKit.Examples.Pricing.PricingContext                                                                       100%
  PatternKit.Examples.Pricing.PricingDemo                                                                         56.7%
  PatternKit.Examples.Pricing.PricingPipeline                                                                      100%
  PatternKit.Examples.Pricing.PricingPipelineBuilder                                                               100%
  PatternKit.Examples.Pricing.PricingResult                                                                        100%
  PatternKit.Examples.Pricing.RegionCategoryTaxPolicy                                                              100%
  PatternKit.Examples.Pricing.Sku                                                                                 85.7%
  PatternKit.Examples.Pricing.SourceRouter                                                                        92.3%
  PatternKit.Examples.PrototypeDemo.PrototypeDemo                                                                  100%
  PatternKit.Examples.ProxyDemo.ProxyDemo                                                                         94.5%
  PatternKit.Examples.Singleton.DeviceRegistry                                                                     100%
  PatternKit.Examples.Singleton.PosAppState                                                                        100%
  PatternKit.Examples.Singleton.PosAppStateDemo                                                                    100%
  PatternKit.Examples.Singleton.PricingCache                                                                       100%
  PatternKit.Examples.Singleton.StoreConfig                                                                        100%
  PatternKit.Examples.StateDemo.OrderStateDemo                                                                     100%
  PatternKit.Examples.Strategies.Coercion.Coercer<T>                                                              83.3%
  PatternKit.Examples.Strategies.Coercion.CoercerExtensions                                                        100%
  PatternKit.Examples.Strategies.Composed.ChannelPolicy                                                            100%
  PatternKit.Examples.Strategies.Composed.ChannelPolicyFactory                                                     100%
  PatternKit.Examples.Strategies.Composed.ComposedStrategies                                                      94.2%
  PatternKit.Examples.Strategies.Composed.SendContext                                                              100%
  PatternKit.Examples.Strategies.Composed.SendResult                                                               100%
  PatternKit.Examples.TemplateDemo.AsyncDataPipeline                                                               100%
  PatternKit.Examples.TemplateDemo.DataProcessor                                                                   100%
  PatternKit.Examples.TemplateDemo.TemplateAsyncFluentDemo                                                         100%
  PatternKit.Examples.TemplateDemo.TemplateFluentDemo                                                               90%
  PatternKit.Examples.TemplateDemo.TemplateMethodDemo                                                              100%
  PatternKit.Examples.VisitorDemo.Card                                                                             100%
  PatternKit.Examples.VisitorDemo.Cash                                                                             100%
  PatternKit.Examples.VisitorDemo.CountersHandler                                                                  100%
  PatternKit.Examples.VisitorDemo.Demo                                                                             100%
  PatternKit.Examples.VisitorDemo.GiftCard                                                                         100%
  PatternKit.Examples.VisitorDemo.ReceiptRendering                                                                 100%
  PatternKit.Examples.VisitorDemo.Routing                                                                          100%
  PatternKit.Examples.VisitorDemo.StoreCredit                                                                      100%
  PatternKit.Examples.VisitorDemo.Tender                                                                           100%
  PatternKit.Examples.VisitorDemo.Unknown                                                                          100%

PatternKit.Generators                                                                                             92.7%
  PatternKit.Generators.Builders.BuilderGenerator                                                                 96.3%
  PatternKit.Generators.DecoratorGenerator                                                                        79.1%
  PatternKit.Generators.Factories.FactoriesGenerator                                                              86.6%
  PatternKit.Generators.MementoGenerator                                                                          94.8%
  PatternKit.Generators.Messaging.DispatcherGenerator                                                             98.1%
  PatternKit.Generators.StrategyGenerator                                                                         93.9%
  PatternKit.Generators.VisitorGenerator                                                                          99.4%

PatternKit.Generators.Abstractions                                                                                  62%
  PatternKit.Generators.Builders.BuilderRequiredAttribute                                                          100%
  PatternKit.Generators.Builders.GenerateBuilderAttribute                                                          100%
  PatternKit.Generators.Decorator.GenerateDecoratorAttribute                                                         0%
  PatternKit.Generators.Factories.FactoryCaseAttribute                                                             100%
  PatternKit.Generators.Factories.FactoryClassAttribute                                                            100%
  PatternKit.Generators.Factories.FactoryClassKeyAttribute                                                         100%
  PatternKit.Generators.Factories.FactoryMethodAttribute                                                           100%
  PatternKit.Generators.GenerateStrategyAttribute                                                                  100%
  PatternKit.Generators.MementoAttribute                                                                             0%
  PatternKit.Generators.MementoStrategyAttribute                                                                     0%
  PatternKit.Generators.Messaging.GenerateDispatcherAttribute                                                        0%
  PatternKit.Generators.Visitors.GenerateVisitorAttribute                                                            0%

@github-actions
Copy link
Contributor

🔍 PR Validation Results

Version: ``

✅ Validation Steps

  • Build solution
  • Run tests
  • Build documentation
  • Dry-run NuGet packaging

📊 Artifacts

Dry-run artifacts have been uploaded and will be available for 7 days.


This comment was automatically generated by the PR validation workflow.

@codecov
Copy link

codecov bot commented Jan 22, 2026

Codecov Report

❌ Patch coverage is 63.41463% with 165 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.15%. Comparing base (c658faa) to head (7047b99).

Files with missing lines Patch % Lines
...Kit.Examples/Decorators/StorageDecoratorExample.cs 3.29% 88 Missing ⚠️
src/PatternKit.Generators/DecoratorGenerator.cs 79.71% 72 Missing ⚠️
...stractions/Decorator/GenerateDecoratorAttribute.cs 0.00% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #91      +/-   ##
==========================================
+ Coverage   85.83%   89.15%   +3.31%     
==========================================
  Files         143      146       +3     
  Lines       12288    12739     +451     
  Branches     1641     1697      +56     
==========================================
+ Hits        10548    11358     +810     
- Misses       1329     1381      +52     
+ Partials      411        0     -411     
Flag Coverage Δ
unittests 89.15% <63.41%> (+3.31%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new Decorator-pattern source generator to produce base decorator implementations (plus optional composition helpers) for interfaces and abstract classes, backed by new attributes, tests, and an example.

Changes:

  • Introduces [GenerateDecorator], [DecoratorIgnore], and DecoratorCompositionMode in the abstractions package.
  • Adds DecoratorGenerator to emit forwarding base decorator types and (optionally) a Compose helper.
  • Adds a new test suite and an examples/demo file showcasing generated decorators.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
src/PatternKit.Generators/DecoratorGenerator.cs Implements the incremental source generator and code emission for decorators/helpers.
src/PatternKit.Generators.Abstractions/Decorator/GenerateDecoratorAttribute.cs Adds public generator surface area (attribute + enum) to configure decorator generation.
src/PatternKit.Generators.Abstractions/Decorator/DecoratorIgnoreAttribute.cs Adds attribute for per-member generation behavior control.
src/PatternKit.Generators/AnalyzerReleases.Unshipped.md Registers new diagnostic IDs for the decorator generator.
test/PatternKit.Generators.Tests/DecoratorGeneratorTests.cs Adds compilation-based tests for generated output.
src/PatternKit.Examples/Decorators/StorageDecoratorExample.cs Adds a real-world example demonstrating decorator chaining and usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JerrettDavis
Copy link
Owner

@copilot apply changes based on the comments in this thread

Copilot AI and others added 3 commits January 22, 2026 15:06
…rwarding, and add comprehensive tests

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Copy link

Copilot AI left a 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 6 out of 6 changed files in this pull request and generated 11 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JerrettDavis
Copy link
Owner

@copilot apply changes based on the comments in this thread

Copilot AI and others added 3 commits January 22, 2026 19:42
… setters, signature deduplication

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
…fix protected member access

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
…m lookup, fix indentation

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Copy link

Copilot AI left a 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 6 out of 6 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// Skip special methods (constructors, operators, property accessors, etc.)
if (method.MethodKind != MethodKind.Ordinary)
continue;

Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

Static members aren’t filtered out. If a contract interface contains static members (including C# 11 static abstract interface members) or static properties, the generator will try to emit instance forwarding members, which won’t compile. Consider detecting IsStatic for methods/properties and reporting PKDEC002 instead of generating invalid code.

Suggested change
// Skip static methods; decorators only forward instance members
if (method.IsStatic)
continue;

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. Static methods now filtered out and ignored silently. Added test to verify static members are not included in generated code.

Comment on lines +269 to +273
var isAsync = IsAsyncMethod(method);
var returnType = method.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

members.Add(new MemberInfo
{
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

Generic methods aren’t handled: the generator records only method.Name and parameters, but never emits method type parameters (<T>) or constraints. Any contract with a generic method (even if the contract type itself is non-generic) will result in uncompilable generated code. Either implement generic method emission or emit PKDEC002 and skip these members.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. Generic methods now emit PKDEC002 diagnostic. Added test for generic method detection.

Comment on lines +309 to +313
// Skip inaccessible properties
if (!IsAccessibleForDecorator(property.DeclaredAccessibility))
{
context.ReportDiagnostic(Diagnostic.Create(
InaccessibleMemberDescriptor,
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

Property forwarding only checks property.DeclaredAccessibility, but accessor accessibility can differ. A common pattern like public string Name { get; protected set; } will pass this check, but the generated setter will call Inner.Name = value; which won’t compile because the setter is protected and Inner is typed as the base contract. The accessibility logic should consider getter/setter accessibility (or omit forwarding for inaccessible accessors) and report PKDEC004/PKDEC002 rather than emitting uncompilable code.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. Now checks accessor-level accessibility separately. Properties with inaccessible accessors (e.g., protected set) emit PKDEC004. Added test for protected setter scenario.

Comment on lines 359 to 367
else if (member is IFieldSymbol or INamedTypeSymbol)
{
// Fields and nested types are not supported
context.ReportDiagnostic(Diagnostic.Create(
UnsupportedMemberDescriptor,
member.Locations.FirstOrDefault(),
member.Name,
member.Kind.ToString()));
}
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

This branch reports PKDEC002 for all fields and nested types returned by type.GetMembers(). For abstract class contracts this will raise errors even for private implementation details (fields/nested types), which makes many real-world abstract classes unusable as contracts. Consider only reporting PKDEC002 for forwardable API-surface members, and silently ignore private/internal implementation details like fields/nested types.

Suggested change
else if (member is IFieldSymbol or INamedTypeSymbol)
{
// Fields and nested types are not supported
context.ReportDiagnostic(Diagnostic.Create(
UnsupportedMemberDescriptor,
member.Locations.FirstOrDefault(),
member.Name,
member.Kind.ToString()));
}
else if (member is IFieldSymbol fieldSymbol)
{
// Fields are not supported; only report for forwardable API-surface members
if (IsAccessibleForDecorator(fieldSymbol.DeclaredAccessibility))
{
context.ReportDiagnostic(Diagnostic.Create(
UnsupportedMemberDescriptor,
member.Locations.FirstOrDefault(),
member.Name,
member.Kind.ToString()));
}
}
else if (member is INamedTypeSymbol typeSymbol)
{
// Nested types are not supported; only report for forwardable API-surface members
if (IsAccessibleForDecorator(typeSymbol.DeclaredAccessibility))
{
context.ReportDiagnostic(Diagnostic.Create(
UnsupportedMemberDescriptor,
member.Locations.FirstOrDefault(),
member.Name,
member.Kind.ToString()));
}
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. PKDEC002 now only reported for accessible fields/nested types. Private implementation details silently ignored.

private static readonly DiagnosticDescriptor InaccessibleMemberDescriptor = new(
id: DiagIdInaccessibleMember,
title: "Member is not accessible for decorator generation",
messageFormat: "Member '{0}' cannot be accessed for decorator forwarding. Ensure the member is public or internal with InternalsVisibleTo.",
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

PKDEC004’s message text is misleading: the generator allows protected internal members, and InternalsVisibleTo doesn’t address the real unsupported case (pure protected/private protected forwarding through Inner). Consider updating the diagnostic message to reflect the actual supported accessibilities and why protected members can’t be forwarded.

Suggested change
messageFormat: "Member '{0}' cannot be accessed for decorator forwarding. Ensure the member is public or internal with InternalsVisibleTo.",
messageFormat: "Member '{0}' cannot be forwarded by the generated decorator. Only members accessible from the decorator type (public, internal, or protected internal, with InternalsVisibleTo as needed) can be forwarded; purely protected or private protected members on the inner type are not accessible.",

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. Updated PKDEC004 message to accurately describe supported accessibilities and explain why pure protected members can't be forwarded.

Comment on lines 5 to 6
/// The generator will still emit a forwarding member in the decorator, but it will
/// strip <c>virtual</c>/<c>override</c> so the member is not decorated or overridden.
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

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

The XML doc says the generator “strips virtual/override” for ignored members, but for abstract-class contracts the generator emits sealed override (it must still override to satisfy the abstract/virtual contract). Please update the doc to match the actual behavior.

Suggested change
/// The generator will still emit a forwarding member in the decorator, but it will
/// strip <c>virtual</c>/<c>override</c> so the member is not decorated or overridden.
/// The generator will still emit a forwarding member in the decorator. For concrete
/// members it strips <c>virtual</c>/<c>override</c> so the member is not decorated,
/// but when required to satisfy an abstract or virtual contract it emits a
/// <c>sealed override</c> instead.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. Updated DecoratorIgnoreAttribute documentation to clarify sealed override behavior for abstract/virtual contracts.

Comment on lines 628 to 640
string modifierKeyword;
if (contractInfo.IsAbstractClass)
{
// For abstract class contracts, always override the contract member.
// If the member is ignored, seal the override to prevent further overriding
// while still satisfying the abstract/virtual contract.
modifierKeyword = member.IsIgnored ? "sealed override " : "override ";
}
else
{
// For non-abstract contracts (e.g., interfaces), only non-ignored members are virtual.
modifierKeyword = member.IsIgnored ? "" : "virtual ";
}
Copy link

Copilot AI Jan 22, 2026

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.

Suggested change
string modifierKeyword;
if (contractInfo.IsAbstractClass)
{
// For abstract class contracts, always override the contract member.
// If the member is ignored, seal the override to prevent further overriding
// while still satisfying the abstract/virtual contract.
modifierKeyword = member.IsIgnored ? "sealed override " : "override ";
}
else
{
// For non-abstract contracts (e.g., interfaces), only non-ignored members are virtual.
modifierKeyword = member.IsIgnored ? "" : "virtual ";
}
string modifierKeyword = contractInfo.IsAbstractClass
// For abstract class contracts, always override the contract member.
// If the member is ignored, seal the override to prevent further overriding
// while still satisfying the abstract/virtual contract.
? (member.IsIgnored ? "sealed override " : "override ")
// For non-abstract contracts (e.g., interfaces), only non-ignored members are virtual.
: (member.IsIgnored ? "" : "virtual ");

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. Simplified to ternary operator for better code clarity.

Comment on lines 707 to 718
string modifierKeyword;
if (contractInfo.IsAbstractClass)
{
// For abstract class contracts, always override.
// If ignored, seal the override to prevent further overriding.
modifierKeyword = member.IsIgnored ? "sealed override " : "override ";
}
else
{
// For interfaces, only non-ignored members are virtual.
modifierKeyword = member.IsIgnored ? "" : "virtual ";
}
Copy link

Copilot AI Jan 22, 2026

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.

Suggested change
string modifierKeyword;
if (contractInfo.IsAbstractClass)
{
// For abstract class contracts, always override.
// If ignored, seal the override to prevent further overriding.
modifierKeyword = member.IsIgnored ? "sealed override " : "override ";
}
else
{
// For interfaces, only non-ignored members are virtual.
modifierKeyword = member.IsIgnored ? "" : "virtual ";
}
string modifierKeyword = contractInfo.IsAbstractClass
? (member.IsIgnored ? "sealed override " : "override ")
: (member.IsIgnored ? "" : "virtual ");

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7783db2. Simplified to ternary operator for better code clarity.

@JerrettDavis
Copy link
Owner

@copilot apply changes based on the comments in this thread

…accessibility, improved diagnostics

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generator: Create Decorator Pattern

2 participants