Skip to content

feat(bloc_lint): add avoid_duplicate_event_handlers - #4851

Open
TiwariAshuism wants to merge 1 commit into
felangel:masterfrom
TiwariAshuism:feat/avoid-duplicate-event-handlers
Open

feat(bloc_lint): add avoid_duplicate_event_handlers#4851
TiwariAshuism wants to merge 1 commit into
felangel:masterfrom
TiwariAshuism:feat/avoid-duplicate-event-handlers

Conversation

@TiwariAshuism

Copy link
Copy Markdown

Status

READY

Breaking Changes

NO

Description

Adds the avoid_duplicate_event_handlers lint rule, which warns when a bloc registers more than one event handler for the same event type.

A Bloc supports a single handler per event type — on<E> throws a StateError when called twice for the same E. Because that check lives inside an assert, it only surfaces in debug mode, so a duplicate registration can otherwise reach production unnoticed.

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) => emit(state + 1));
    on<CounterIncrementPressed>((event, emit) => emit(state + 10)); // LINT
  }
}

Implementation notes

  • Hooks endTypeArguments so the parser resolves the balanced type argument group. Nested generics such as on<MyEvent<String>> work without hand-rolled >> splitting, and MyEvent<String> / MyEvent<int> are correctly treated as distinct event types.
  • Scoped via handleClassExtends to classes whose superclass ends in Bloc, which covers Bloc, HydratedBloc and ReplayBloc and avoids class-level type parameters confusing the extends lookup.
  • Skips member access (registry.on<T>(...)) and on clauses in try/catch.
  • Detection is per-class and also catches handlers registered outside the constructor.

Known limitation: handlers registered in mutually exclusive branches (if (x) on<E>(a); else on<E>(b);) are flagged. // ignore: avoid_duplicate_event_handlers covers that case.

Two decisions I would like your call on

  1. Severity is warning, matching the other avoid_* rules. error may be more appropriate given this is a guaranteed runtime failure rather than a style preference — happy to change it.
  2. Not added to recommended.yaml, following the precedent in feat(bloc_lint): add avoid_bloc_to_bloc_members #4665. It may be a reasonable recommended candidate since it catches code that is certain to throw.

Verified locally against the CI gates: dart format, dart analyze --fatal-warnings lib test, full suite (165 tests, 14 new) and 100% coverage.

Closes #4460

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

Warn when a bloc registers more than one event handler for the same
event type. `on<E>` supports a single handler per event type and throws
a `StateError` when called twice for the same `E`, but because the check
runs inside an assert it only surfaces in debug mode.

The rule hooks `endTypeArguments` so the parser resolves the balanced
type argument group, which keeps nested generics such as
`on<MyEvent<String>>` working without hand-rolled `>>` handling.

Closes felangel#4460
@TiwariAshuism
TiwariAshuism requested a review from felangel as a code owner August 1, 2026 20:54
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.

feat(bloc_lint): avoid_duplicate_event_handlers

1 participant