handle-bloc-event-subclasses
- Group
- Correctness
- Path
lint/correctness/handle-bloc-event-subclasses- Default
- Off, opt in
- Origin
- Falcon
- Domain
- bloc
- Rule
- 241 of 512
Warns when a Bloc constructor leaves a concrete event subclass without a handler.
Register a handler for every event subclass, or register a handler for their
parent event. This rule checks event classes declared in the same file and
on<Event> registrations in each generative constructor, including cascades.
Handler coverage compares full event instantiations and accepts unknown subtyping.
Inferred registrations conservatively count as coverage. Factories, redirects,
abstract event classes, generic event roots and overridden on APIs are ignored.
Calls to instance helpers on this, including inherited helpers, count as
unresolved coverage.
Invalid
import 'package:bloc/bloc.dart';
sealed class Event {}
final class Start extends Event {}
final class Stop extends Event {}
class CounterBloc extends Bloc<Event, int> {
CounterBloc() : super(0) {
on<Start>((event, emit) {});
}
CounterBloc.empty() : super(0) {}
CounterBloc.partialCascade() : super(0) {
this..on<Start>((event, emit) {});
}
CounterBloc.otherReceiver(Bloc<Event, int> other) : super(0) {
other
..on<Start>((event, emit) {})
..on<Stop>((event, emit) {});
}
CounterBloc.localOn() : super(0) {
void on(Object handler) {}
on((Event event, Emitter<int> emit) {});
}
}
abstract class GenericEvent {}
abstract class Value<T> extends GenericEvent {}
class IntValue extends Value<int> {}
class MismatchedValueBloc extends Bloc<GenericEvent, int> {
MismatchedValueBloc() : super(0) {
on<Value<String>>((event, emit) {});
}
}
class UnrelatedHelperBloc extends Bloc<Event, int> {
UnrelatedHelperBloc.other(UnrelatedHelperBloc other) : super(0) {
other._registerHandlers();
}
UnrelatedHelperBloc.shadowed() : super(0) {
void _registerHandlers() {}
_registerHandlers();
}
UnrelatedHelperBloc.staticCall() : super(0) {
_staticHelper();
}
UnrelatedHelperBloc.addEvent() : super(0) {
on<Start>((event, emit) {});
add(Start());
}
UnrelatedHelperBloc.explicitAddEvent() : super(0) {
on<Start>((event, emit) {});
this.add(Start());
}
void _registerHandlers() {
on<Start>((event, emit) {});
on<Stop>((event, emit) {});
}
static void _staticHelper() {}
}class CounterBloc extends Bloc<Event, int> { CounterBloc() : super(0) { } CounterBloc.empty() : super(0) {} CounterBloc.empty() : super(0) {} CounterBloc.partialCascade() : super(0) { } CounterBloc.otherReceiver(Bloc<Event, int> other) : super(0) { } CounterBloc.localOn() : super(0) {class MismatchedValueBloc extends Bloc<GenericEvent, int> { MismatchedValueBloc() : super(0) {class UnrelatedHelperBloc extends Bloc<Event, int> { UnrelatedHelperBloc.other(UnrelatedHelperBloc other) : super(0) { } UnrelatedHelperBloc.shadowed() : super(0) { } UnrelatedHelperBloc.staticCall() : super(0) { } UnrelatedHelperBloc.addEvent() : super(0) { } UnrelatedHelperBloc.explicitAddEvent() : super(0) {Valid
import 'package:bloc/bloc.dart';
sealed class Event {}
final class Start extends Event {}
final class Stop extends Event {}
class CompleteBloc extends Bloc<Event, int> {
CompleteBloc() : super(0) {
on<Start>((event, emit) {});
on<Stop>((event, emit) {});
}
CompleteBloc.parent() : super(0) {
on<Event>((event, emit) {});
}
CompleteBloc.redirect() : this();
CompleteBloc.inferred() : super(0) {
on((Event event, Emitter<int> emit) {});
}
CompleteBloc.cascade() : super(0) {
this
..on<Start>((event, emit) {})
..on<Stop>((event, emit) {});
}
CompleteBloc.inferredCascade() : super(0) {
this..on((Event event, Emitter<int> emit) {});
}
CompleteBloc.cascadeWithLocalOn() : super(0) {
void on<T>(Object handler) {}
this
..on<Start>((event, emit) {})
..on<Stop>((event, emit) {});
}
}
class NotABloc {
NotABloc();
}
class GenericBloc<Event extends Object> extends Bloc<Event, int> {
GenericBloc() : super(0) {
on<Event>((event, emit) {});
}
}
abstract class GenericEvent {}
abstract class Value<T> extends GenericEvent {}
class IntValue extends Value<int> {}
class MatchingValueBloc extends Bloc<GenericEvent, int> {
MatchingValueBloc() : super(0) {
on<Value<int>>((event, emit) {});
}
MatchingValueBloc.raw() : super(0) {
on<Value>((event, emit) {});
}
MatchingValueBloc.dynamicArgument() : super(0) {
on<Value<dynamic>>((event, emit) {});
}
}
abstract class UnresolvedEvent {}
abstract class UnknownValue<T> extends UnresolvedEvent {}
class FooValue extends UnknownValue<Foo> {}
class UnresolvedValueBloc extends Bloc<UnresolvedEvent, int> {
UnresolvedValueBloc() : super(0) {
on<UnknownValue<Foo>>((event, emit) {});
}
}
abstract class WrappedEvent {}
abstract class WrappedValue<T> extends WrappedEvent {}
class Wrapped<T> extends WrappedValue<T> {}
class WrappedValueBloc extends Bloc<WrappedEvent, int> {
WrappedValueBloc() : super(0) {
on<WrappedValue<int>>((event, emit) {});
}
}
class HelperBloc extends Bloc<Event, int> {
HelperBloc() : super(0) {
_registerHandlers();
}
HelperBloc.explicitThis() : super(0) {
this._registerHandlers();
}
void _registerHandlers() {
on<Start>((event, emit) {});
on<Stop>((event, emit) {});
}
}
mixin HandlerRegistration on Bloc<Event, int> {
void _registerHandlers() {
on<Start>((event, emit) {});
on<Stop>((event, emit) {});
}
}
class MixinHelperBloc extends Bloc<Event, int> with HandlerRegistration {
MixinHelperBloc() : super(0) {
_registerHandlers();
}
MixinHelperBloc.explicitThis() : super(0) {
this._registerHandlers();
}
}Configure handle-bloc-event-subclasses
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"handle-bloc-event-subclasses": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/handle-bloc-event-subclasses: <reason>More correctness rules
- hash-and-equals
hash_and_equalsrecommendedRequire
hashCodeand==to be overridden together. - implementation-imports
implementation_importsrecommendedDisallow importing another package's private
src/libraries. - implicit-reopen
implicit_reopenFlags classes that implicitly reopen a supertype declared in the same library.
- invalid-case-patterns
invalid_case_patternsrecommendedFlags pre-3.0 switch case expressions that change meaning or break under Dart 3 patterns.
- invalid-runtime-check-with-js-interop-types
invalid_runtime_check_with_js_interop_typesrecommendedReject platform-dependent runtime checks involving JavaScript interop types.
- library-private-types-in-public-api
library_private_types_in_public_apirecommendedAvoid using library-private types in public APIs.
- list-all-equatable-fieldsrecommendedequatable
Flags declared instance fields omitted from a statically understood Equatable props list.
- literal-only-boolean-expressions
literal_only_boolean_expressionsrecommendedFlags conditions built only from literals, whose value never changes.