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,
) {
context.addClassDeclaration((ClassDeclaration node) {
// Check if class extends Bloc
final ExtendsClause? extendsClause = node.extendsClause;
if (extendsClause == null) return;
final String superclassName = extendsClause.superclass.name.lexeme;
if (superclassName != 'Bloc') return;
// Find constructor
ConstructorDeclaration? constructor;
for (final ClassMember member in node.bodyMembers) {
if (member is ConstructorDeclaration && member.name == null) {
constructor = member;
break;
}
}
if (constructor == null) return;
// Find all on<Event> calls
final Map<String, List<MethodInvocation>> eventHandlers =
<String, List<MethodInvocation>>{};
final _OnCallVisitor visitor = _OnCallVisitor();
constructor.body.accept(visitor);
for (final MethodInvocation onCall in visitor.onCalls) {
final TypeArgumentList? typeArgs = onCall.typeArguments;
if (typeArgs == null || typeArgs.arguments.isEmpty) continue;
final String eventType = typeArgs.arguments.first.toSource();
eventHandlers
.putIfAbsent(eventType, () => <MethodInvocation>[])
.add(onCall);
}
// Report duplicates
for (final String eventType in eventHandlers.keys) {
final List<MethodInvocation>? handlers = eventHandlers[eventType];
if (handlers != null && handlers.length > 1) {
// Report all but the first one
for (int i = 1; i < handlers.length; i++) {
reporter.atNode(handlers[i], code);
}
}
}
});
}