run method

  1. @override
void run(
  1. CustomLintResolver resolver,
  2. DiagnosticReporter reporter,
  3. CustomLintContext context
)

Emits lints for a given file.

run will only be invoked with files respecting filesToAnalyze

Implementation

@override
void run(
  CustomLintResolver resolver,
  DiagnosticReporter reporter,
  CustomLintContext context,
) {
  context.registry.addInstanceCreationExpression((node) {
    final type = node.staticType;
    if (type == null) {
      return;
    }

    final typeName = type.element?.name;

    // Check for common Flutter button widgets
    final buttonTypes = [
      'ElevatedButton',
      'TextButton',
      'OutlinedButton',
      'IconButton',
      'FloatingActionButton',
      'CupertinoButton',
    ];

    if (!buttonTypes.contains(typeName)) {
      return;
    }

    // Look for onPressed or onTap arguments
    final arguments = node.argumentList.arguments;
    for (final arg in arguments) {
      if (arg is NamedExpression) {
        final paramName = arg.name.label.name;

        if (paramName == 'onPressed' || paramName == 'onTap') {
          final expression = arg.expression;

          // Check if it's explicitly null
          if (expression is NullLiteral) {
            // Null is acceptable for disabled state
            continue;
          }

          // Check for empty function bodies: () {}
          // AST-based check for no-op callbacks
          if (expression is FunctionExpression) {
            final body = expression.body;
            // Check for empty block body: () {}
            if (body is BlockFunctionBody && body.block.statements.isEmpty) {
              reporter.atNode(node, code);
            }
            // Check for empty function body: () ;
            else if (body is EmptyFunctionBody) {
              reporter.atNode(node, code);
            }
            // Check for expression body: () => null
            else if (body is ExpressionFunctionBody) {
              final expr = body.expression;
              if (expr is NullLiteral) {
                reporter.atNode(node, code);
              }
            }
          }
        }
      }
    }
  });
}