prefer-extracting-callbacks

Same as prefer-extracting-callbacks in Dart Code Metrics

Path
lint/complexity/prefer-extracting-callbacks
Default
Off, opt in
Origin
Dart Code Metrics
Domain
flutter
Rule
353 of 512
flutter

Flags inline block-body callbacks passed to Widget constructors.

The rule uses resolved Flutter identities for both the containing Widget class and each constructed Widget. Calls that cannot be resolved uniquely are left alone; spelling, capitalization, and import-prefix shape are not evidence.

allowed-line-count (optional integer, default: unset) permits callbacks up to that many lines. ignored-named-arguments (string array, default: empty) excludes matching named arguments from callback checks.

Invalid

example.dartdart
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as f;

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        final now = DateTime.now();
        doSomething(now);
      },
      child: const Text('go'),
    );
  }
}

class MyState extends State<MyWidget> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {});
        doSomething(null);
      },
      child: const Text('tap'),
    );
  }
}

class PrefixedWidget extends f.StatelessWidget {
  @override
  f.Widget build(f.BuildContext context) => f.ElevatedButton(
    onPressed: () {
      final value = DateTime.now();
      doSomething(value);
    },
  );
}

void doSomething(Object? x) {}

class NestedClosureReturn extends StatelessWidget {
  @override
  Widget build(BuildContext context) => ElevatedButton(
    onPressed: () {
      final nested = () {
        return const Text('nested');
      };
      doSomething(nested);
    },
  );
}
Prefer extracting the callback to a separate widget method.
9 return ElevatedButton(
10 onPressed: () {
Prefer extracting the callback to a separate widget method.
22 return GestureDetector(
23 onTap: () {
Prefer extracting the callback to a separate widget method.
34 f.Widget build(f.BuildContext context) => f.ElevatedButton(
35 onPressed: () {
Prefer extracting the callback to a separate widget method.
46 Widget build(BuildContext context) => ElevatedButton(
47 onPressed: () {

Valid

example.dartdart
import 'package:flutter/material.dart';

// Non-widget class: callbacks are never flagged (dcl only visits Widget/State).
class NotAWidget {
  void run(List<int> items) {
    items.forEach((item) {
      final doubled = item * 2;
      print(doubled);
    });
  }
}

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  final int mode = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Arrow callback: not a block body, never flagged.
        ElevatedButton(
          onPressed: () => doSomething(),
          child: const Text('go'),
        ),
        // Single-line block callback: within allowed_line_count, not flagged.
        ElevatedButton(
          onPressed: () { doSomething(); },
          child: const Text('short'),
        ),
        // Builder callback (first parameter is BuildContext) is excluded.
        Builder(
          builder: (BuildContext context) {
            final theme = Theme.of(context);
            return Text('$theme');
          },
        ),
        // Untyped builder parameter: unresolved, still treated as a builder.
        Builder(
          builder: (context) {
            final label = 'value';
            return Text(label);
          },
        ),
        // Widget returned only from nested branches still counts as a builder.
        Builder(
          builder: (BuildContext context) {
            switch (mode) {
              case 0:
                return const Text('a');
              default:
                return const Text('b');
            }
          },
        ),
      ],
    );
  }
}

void doSomething() {}

class LocalFunctionReturn extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Builder(
    builder: (BuildContext context) {
      Widget local() {
        return const Text('local');
      }
      return local();
    },
  );
}

Configure prefer-extracting-callbacks

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "complexity": {
        "prefer-extracting-callbacks": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/complexity/prefer-extracting-callbacks: <reason>