runWithReporter method

  1. @override
void runWithReporter(
  1. SaropaDiagnosticReporter reporter,
  2. SaropaContext context
)
override

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) {
    // Skip abstract classes — abstract final class is the correct pattern
    // for non-instantiable namespaces (handled by
    // prefer_abstract_final_static_class instead)
    if (node.abstractKeyword != null) return;

    // Skip if class extends something other than Object
    if (node.extendsClause != null) return;

    // Skip if class has mixins or implements interfaces
    if (node.withClause != null || node.implementsClause != null) return;

    // Check if all members are static
    bool hasNonStaticMember = false;
    bool hasStaticMember = false;
    bool hasPrivateConstructor = false;

    for (final ClassMember member in node.bodyMembers) {
      if (member is ConstructorDeclaration) {
        final String? name = member.name?.lexeme;
        if (name != null && name.startsWith('_')) {
          // Private constructor — prefer_abstract_final_static_class
          // handles this case instead.
          hasPrivateConstructor = true;
        } else if (member.factoryKeyword == null) {
          hasNonStaticMember = true;
        }
      } else if (member is FieldDeclaration) {
        if (member.isStatic) {
          hasStaticMember = true;
        } else {
          hasNonStaticMember = true;
        }
      } else if (member is MethodDeclaration) {
        if (member.isStatic) {
          hasStaticMember = true;
        } else {
          hasNonStaticMember = true;
        }
      }
    }

    if (hasStaticMember && !hasNonStaticMember && !hasPrivateConstructor) {
      reporter.atToken(node.nameToken, code);
    }
  });
}