runWithReporter method
Override this method to implement your lint rule.
Use context to register callbacks for AST node types:
context.addMethodInvocation((node) {
if (condition) {
reporter.atNode(node);
}
});
Implementation
@override
void runWithReporter(
SaropaDiagnosticReporter reporter,
SaropaContext context,
) {
// A class named `...State` is only a genuine BLoC state if it participates
// in a Bloc/Cubit state hierarchy (referenced as a `Bloc<_, ThisState>` /
// `Cubit<ThisState>` type argument). The previous version reported any
// concrete `...State`-named class in a bloc file purely by name, so a plain
// domain object such as `RequestState` was a false positive. Because a
// Bloc/Cubit declaration may textually precede OR follow its state class,
// gating needs the whole unit in hand — so we visit the compilation unit
// once (a single visitor that the native registry supports; the v4
// addPostRunCallback is a no-op here and cannot be used) and run two passes
// over its top-level declarations.
context.addCompilationUnit((CompilationUnit unit) {
// Pass 1: collect every name used as a `Bloc<...>` / `Cubit<...>` type
// argument anywhere in the unit. We collect ALL type arguments (not just
// the state position) so the gate is robust to `Bloc<Event, State>` vs
// `Cubit<State>` shapes; a `...State` name only matters when it actually
// appears here.
final Set<String> blocStateTypeArgNames = <String>{};
for (final CompilationUnitMember member in unit.declarations) {
if (member is ClassDeclaration) {
_collectBlocStateTypeArgs(member, blocStateTypeArgNames);
}
}
// Pass 2: report mutable `...State` classes that participate as a
// Bloc/Cubit state type argument.
for (final CompilationUnitMember member in unit.declarations) {
if (member is ClassDeclaration) {
_checkStateClass(member, blocStateTypeArgNames, reporter);
}
}
});
}