unreachable-from-main

Same as unreachable_from_main in Dart lints

Group
Style
Path
lint/style/unreachable-from-main
Default
Off, opt in
Origin
Dart lints
Rule
477 of 512

Report public declarations that no entry point of an executable library reaches.

A library — its defining unit plus every part file — is executable when it declares a top-level function named main, or a top-level function annotated @pragma('vm:entry-point') whose pragma provably resolves to dart:core. Starting from those entry points (and from top-level functions annotated with a widget-preview @Preview), the rule follows references: identifiers, invocations, constructor names and tear-offs, annotations, user-defined operators, object-pattern fields, doc comment references, supertypes named in a class's extends/with/implements clause or an extension type's implements clause, implicit super-constructor calls, typedef and extension-type names, type literals, type arguments, and the types of external members. Type parameters shadow same-named library declarations. A plain type annotation is not a reference, and constructor invocations inside constant patterns do not count. Instance toJson methods are reachable with their container, because dart:convert calls them dynamically. Documentation references use the shared Dartdoc parser, excluding Markdown link display text and link definitions, inline and block code, and Dartdoc directives. Reference-style destination labels remain references. A block documentation comment replaces immediately preceding line docs, following the shared documentation grouping used by other rules.

The candidates are the library's top-level declarations and the public constructors (except enum constructors), fields, methods, getters, setters, and operators of public classes, enums, mixins, extensions, and extension types. A member that overrides a supertype member is not a candidate, nor are the test-harness methods test_*, solo_test_*, setUp, tearDown, setUpClass, and tearDownClass. Unreached public candidates are reported unless annotated @visibleForTesting or a widget preview; a member other than a field is not reported again when its enclosing declaration already is (the analyzer reports unreachable fields of an unreachable class too). Libraries that declare a top-level name twice are not analyzed.

Facts falcon cannot prove are resolved toward reachability, so uncertainty causes misses rather than false positives: a member whose container has a supertype with an incomplete indexed hierarchy may override it and is not a candidate. Known receiver types resolve members and operators before considering extensions. An unknown receiver reaches same-named members only in extensions or classes named outside their own declaration (a class never named cannot be its static type); an identifier counts unless it resolves to a local. A library with a part that does not resolve to an analyzed file is not analyzed.

Invalid

example.dartdart
void main() {
  Used();
  print(Used.new);
  Child();
  Holder().value;
  print(Shade.dark);
  helper();
  var shadowed = 1;
  print(shadowed);
  Object probe = 1;
  if (probe is OnlyInIsCheck) {}
  if (probe case const OnlyInConstantPattern()) {}
  Shadower().run();
  if (probe case OnlyInObjectPattern()) {}
  dynamic untyped = probe;
  untyped.sharedName();
}

void helper() {}

class NeverNamed {
  void sharedName() {}
}

class Shadower {
  void run() {
    print(label());
  }

  String label() => 'member';
}

String label() => 'top-level';

void orphanFunction() {}

int orphanVariable = 1;

int shadowed = 2;

int get orphanGetter => 7;

set orphanSetter(int value) {}

typedef OrphanAlias = String;

class OrphanClass {
  void memberOfUnreachableClass() {}
}

class OrphanWithField {
  int orphanField = 0;
  static const orphanConstant = 1;
}

mixin OrphanMixin {}

enum OrphanEnum { a, b }

extension OrphanExtension on int {}

extension type OrphanExtensionType(int value) {}

@pragma('other')
void unrelatedPragma() {}

void setUpClass() {}

class Used {
  Used();
  Used.named();

  void unusedMethod() {}
  int? unusedField;
  static void unusedStatic() {}
  int get unusedGetter => 0;
  set unusedSetter(int value) {}
  Used operator +(Used other) => this;
}

class Base {
  void overridden() {}
}

class Child extends Base {
  @override
  void overridden() {}
}

class OnlyInTypeAnnotation {}

class Holder {
  OnlyInTypeAnnotation? value;
}

class OnlyInIsCheck {}

class OnlyInConstantPattern {
  const OnlyInConstantPattern();
}

class OnlyInObjectPattern {}

enum Shade {
  dark,
  light;

  static void unusedEnumStatic() {}
}

extension IntExtension on int {
  void unusedExtensionMethod() {}
}
Unreachable member `NeverNamed` in an executable library.
20
21class NeverNamed {
Unreachable member `label` in an executable library.
32
33String label() => 'top-level';
Unreachable member `orphanFunction` in an executable library.
34
35void orphanFunction() {}
Unreachable member `orphanVariable` in an executable library.
36
37int orphanVariable = 1;
Unreachable member `shadowed` in an executable library.
38
39int shadowed = 2;
Unreachable member `orphanGetter` in an executable library.
40
41int get orphanGetter => 7;
Unreachable member `orphanSetter` in an executable library.
42
43set orphanSetter(int value) {}
Unreachable member `OrphanAlias` in an executable library.
44
45typedef OrphanAlias = String;
Unreachable member `OrphanClass` in an executable library.
46
47class OrphanClass {
Unreachable member `OrphanWithField` in an executable library.
50
51class OrphanWithField {
Unreachable member `orphanField` in an executable library.
51class OrphanWithField {
52 int orphanField = 0;
Unreachable member `orphanConstant` in an executable library.
52 int orphanField = 0;
53 static const orphanConstant = 1;
Unreachable member `OrphanMixin` in an executable library.
55
56mixin OrphanMixin {}
Unreachable member `OrphanEnum` in an executable library.
57
58enum OrphanEnum { a, b }
Unreachable member `OrphanExtension` in an executable library.
59
60extension OrphanExtension on int {}
Unreachable member `OrphanExtensionType` in an executable library.
61
62extension type OrphanExtensionType(int value) {}
Unreachable member `unrelatedPragma` in an executable library.
64@pragma('other')
65void unrelatedPragma() {}
Unreachable member `setUpClass` in an executable library.
66
67void setUpClass() {}
Unreachable member `Used.named` in an executable library.
70 Used();
71 Used.named();
Unreachable member `unusedMethod` in an executable library.
72
73 void unusedMethod() {}
Unreachable member `unusedField` in an executable library.
73 void unusedMethod() {}
74 int? unusedField;
Unreachable member `unusedStatic` in an executable library.
74 int? unusedField;
75 static void unusedStatic() {}
Unreachable member `unusedGetter` in an executable library.
75 static void unusedStatic() {}
76 int get unusedGetter => 0;
Unreachable member `unusedSetter` in an executable library.
76 int get unusedGetter => 0;
77 set unusedSetter(int value) {}
Unreachable member `+` in an executable library.
77 set unusedSetter(int value) {}
78 Used operator +(Used other) => this;
Unreachable member `overridden` in an executable library.
81class Base {
82 void overridden() {}
Unreachable member `OnlyInTypeAnnotation` in an executable library.
89
90class OnlyInTypeAnnotation {}
Unreachable member `OnlyInIsCheck` in an executable library.
95
96class OnlyInIsCheck {}
Unreachable member `OnlyInConstantPattern` in an executable library.
97
98class OnlyInConstantPattern {
Unreachable member `OnlyInObjectPattern` in an executable library.
101
102class OnlyInObjectPattern {}
Unreachable member `unusedEnumStatic` in an executable library.
107
108 static void unusedEnumStatic() {}
Unreachable member `IntExtension` in an executable library.
110
111extension IntExtension on int {

Valid

example.dartdart
import 'dart:convert';

import 'package:meta/meta.dart';

/// The entry point; see [DocumentedOnly] and [Service.describe].
void main() {
  final service = Service.create();
  service.run();
  service.counter += 1;
  print(service[0]);
  print(-service);
  print(service + 1);
  print(TypeLiteralOnly);
  print(<TypeArgumentOnly>[]);
  Callback? callback;
  callback = () {};
  callback();
  print(1 as Wrapped);
  print(jsonEncode([Serializable()]));
  print(Palette.red.label);
  print(Box(1).unwrap());
  final point = Point(1, 2);
  if (point case Point(:final x)) {
    print(x + point.y);
  }
  print(Derived().inherited());
  print(Holder.instance);
  print(OutsideError().detail);
  topLevelSetter = 3;
  print(topLevelGetter);
  annotatedByConstant();
}

class DocumentedOnly {}

class Service {
  Service._();

  factory Service.create() = Service._;

  int counter = 0;

  void run() {
    _helper();
  }

  void _helper() {}

  static void describe() {}

  int operator [](int index) => index;

  Service operator -() => this;

  Service operator +(int other) => this;

  @visibleForTesting
  void inspect() {}

  void test_harnessMethod() {}

  void setUp() {}
}

class TypeLiteralOnly {}

class TypeArgumentOnly {}

typedef Callback = void Function();

extension type Wrapped(int value) {}

class Serializable {
  List<Object> toJson() => const ['value'];
}

enum Palette {
  red('red');

  const Palette(this.label);

  final String label;
}

class Box<T> {
  Box(this.value);

  final T value;

  T unwrap() => value;
}

class Point {
  Point(this.x, this.y);

  final int x;
  final int y;
}

class Parent {
  Parent();

  String inherited() => 'parent';
}

class Derived extends Parent {}

class Holder {
  static final Holder instance = Holder._();

  Holder._();
}

class OutsideError extends Error {
  String get detail => 'outside';
}

set topLevelSetter(int value) {}

int get topLevelGetter => 0;

const entry = pragma('vm:entry-point');

@entry
void annotatedByConstant() {}

@pragma('vm:entry-point')
void nativeCallback() {
  calledFromCallback();
}

void calledFromCallback() {}

@visibleForTesting
void testOnlyHook() {}

Configure unreachable-from-main

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "unreachable-from-main": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/style/unreachable-from-main: <reason>
  • use-colored-boxuse_colored_boxrecommendedflutter

    Prefers ColoredBox over a Container that only paints a color behind its child.

  • use-decorated-boxuse_decorated_boxrecommendedflutter

    Prefers DecoratedBox over a Container that only decorates its child.

  • use-design-system-itemuse-design-system-itemflutter

    Flags construction of a widget or type that should be replaced by its design-system equivalent.

  • use-enumsuse_enums

    Flags classes that emulate an enum and could be declared as one.

  • use-existing-destructuring

    Reuse or extend an existing record destructuring instead of rereading a field.

  • use-existing-variable

    Reuse a local for stable SDK arithmetic and String.length/int parity getters.

  • use-full-hex-values-for-flutter-colorsuse_full_hex_values_for_flutter_colorsrecommendedflutter

    Require an eight-digit hexadecimal integer for the canonical Flutter Color default constructor.

  • use-function-type-syntax-for-parametersuse_function_type_syntax_for_parametersrecommended

    Flags an old-style function-typed parameter written with inline parameter syntax.