import 'dart:async'; import 'bloc.dart'; /// A single-class state with a loading flag and no variant union — the style /// that the variant-based rules cannot see. class FlagEvent {} class FlagRefresh extends FlagEvent {} class FlagReload extends FlagEvent {} class FlagState { const FlagState({this.items = const [], this.loading = true}); final List items; final bool loading; FlagState copyWith({List? items, bool? loading}) => FlagState( items: items ?? this.items, loading: loading ?? this.loading, ); } class FlagCubit extends Bloc { FlagCubit() : super(const FlagState()); /// BAD: puts `loading: true` in flight, then awaits with no catch at all. Future loadUnguarded() async { emit(state.copyWith(loading: true)); await Future.delayed(Duration.zero); emit(state.copyWith(loading: false)); } /// GOOD: the awaited work is inside a try whose catch resets the flag. Future loadGuarded() async { emit(state.copyWith(loading: true)); try { await Future.delayed(Duration.zero); emit(state.copyWith(loading: false)); } catch (error) { emit(state.copyWith(loading: false)); } } /// GOOD: awaits but never puts the loading flag in flight. Future refreshQuietly() async { await Future.delayed(Duration.zero); } /// GOOD: the flag, the await and the guarding catch all live in a closure, /// which is analysed on its own. The enclosing method sets nothing and awaits /// nothing itself, so reporting it would be a false positive. void scheduleGuarded() { _later(() async { emit(state.copyWith(loading: true)); try { await Future.delayed(Duration.zero); } catch (error) { emit(state.copyWith(loading: false)); } }); } void _later(Future Function() work) {} /// BAD, twice: two unguarded handlers in one class. Each is its own finding /// with its own fingerprint, not one `` that hides the other. void registerHandlers() { on((event, emit) async { emit(state.copyWith(loading: true)); await Future.delayed(Duration.zero); }); on((event, emit) async { emit(state.copyWith(loading: true)); await Future.delayed(Duration.zero); }); } }