diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 41fe279b3d4..b05ae1cb8a2 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py @@ -430,8 +430,6 @@ def _CheckAnalyzerFiles(input_api, output_api): # content, when `pkg/analyzer/messages.yaml` is modified. # * Verify that `diagnostics/generate.dart` does not produce different # content, when `pkg/analyzer/messages.yaml` is modified. - # * Verify that `machine.json` is not outdated, when any - # `pkg/linter/lib/src/rules` file is modified. # * Maybe "verify_no_solo" for individual modified (not deleted test files # in Analyzer-team-owned directories. diff --git a/pkg/linter/test/all.dart b/pkg/linter/test/all.dart index a0bb46d6cc3..9561ba3ee88 100644 --- a/pkg/linter/test/all.dart +++ b/pkg/linter/test/all.dart @@ -25,7 +25,6 @@ import 'validate_rule_description_format_test.dart' as validate_rule_description_format; import 'verify_checks_test.dart' as verify_checks; import 'verify_generated_codes_test.dart' as verify_generated_codes; -import 'verify_machine_json_test.dart' as verify_machine_json; import 'verify_reflective_test_suites_test.dart' as verify_reflective_test_suites; @@ -51,6 +50,5 @@ void main() { validate_rule_description_format.main(); verify_checks.main(); verify_generated_codes.main(); - verify_machine_json.main(); verify_reflective_test_suites.main(); } diff --git a/pkg/linter/test/verify_machine_json_test.dart b/pkg/linter/test/verify_machine_json_test.dart deleted file mode 100644 index 31b64f2ecb3..00000000000 --- a/pkg/linter/test/verify_machine_json_test.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -void main() { - // TODO(pq): re-enable when we're reading from DEPS or from a stable published version - // see: https://github.com/dart-lang/linter/issues/4756 - - // group('machine output tests', () { - // setUp(setUpSharedTestEnvironment); - // test("ensure 'rules.json' is up to date", () async { - // var rulesFile = machineJsonFile(); - // var onDisk = rulesFile.readAsStringSync(); - // var generated = await generateRulesJson(); - // expect( - // generated, - // onDisk, - // reason: "'rules.json' is out of date. Regenerate by running " - // '`dart tool/machine.dart -w`', - // ); - // }); - // }); -} diff --git a/pkg/linter/tool/cli.dart b/pkg/linter/tool/cli.dart index b69c73cc102..5c1f093801d 100644 --- a/pkg/linter/tool/cli.dart +++ b/pkg/linter/tool/cli.dart @@ -18,7 +18,7 @@ import 'package:linter/src/test_utilities/analyzer_utils.dart'; import 'package:linter/src/test_utilities/formatter.dart'; import 'package:linter/src/test_utilities/test_linter.dart'; -import 'util/score_utils.dart'; +import 'lint_sets.dart'; /// Starts linting from the command-line. Future main(List args) async { @@ -186,9 +186,9 @@ Future writeBenchmarks( }); } - var coreRuleset = await coreRules; - var recommendedRuleset = await recommendedRules; - var flutterRuleset = await flutterRules; + var coreRuleset = await dartCoreLints; + var recommendedRuleset = await dartRecommendedLints; + var flutterRuleset = await flutterUserLints; var stats = timings.keys.map((t) { var sets = []; diff --git a/pkg/linter/tool/crawl.dart b/pkg/linter/tool/crawl.dart deleted file mode 100644 index 5fd75cac6d3..00000000000 --- a/pkg/linter/tool/crawl.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:analyzer/src/lint/registry.dart'; -import 'package:linter/src/analyzer.dart'; -import 'package:linter/src/rules.dart'; - -import 'util/score_utils.dart' as score_utils; - -// TODO(pq): reign in the nullable types - -final _flutterOptionsUrl = Uri.https('raw.githubusercontent.com', - '/flutter/packages/main/packages/flutter_lints/lib/flutter.yaml'); -final _flutterRepoOptionsUrl = Uri.https( - 'raw.githubusercontent.com', '/flutter/flutter/main/analysis_options.yaml'); - -List? _flutterRepoRules; -List? _flutterRules; -Iterable? _registeredLints; - -Future> get flutterRepoRules async => - _flutterRepoRules ??= await score_utils.fetchRules(_flutterRepoOptionsUrl); - -Future> get flutterRules async => - _flutterRules ??= await score_utils.fetchRules(_flutterOptionsUrl); - -Iterable get registeredLints { - if (_registeredLints == null) { - registerLintRules(); - _registeredLints = Registry.ruleRegistry; - } - return _registeredLints!; -} diff --git a/pkg/linter/tool/lint_sets.dart b/pkg/linter/tool/lint_sets.dart new file mode 100644 index 00000000000..51004488552 --- /dev/null +++ b/pkg/linter/tool/lint_sets.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; + +import 'package:analyzer/src/lint/config.dart'; +import 'package:http/http.dart' as http; +import 'package:linter/src/utils.dart'; + +Future> get dartCoreLints => + _fetchRulesFromGitHub('/dart-lang/lints/blob/main/lib/core.yaml'); + +Future> get dartRecommendedLints => + _fetchRulesFromGitHub('/dart-lang/lints/blob/main/lib/recommended.yaml'); + +Future> get flutterRepoLints => + _fetchRulesFromGitHub('/flutter/flutter/main/analysis_options.yaml'); + +Future> get flutterUserLints => _fetchRulesFromGitHub( + '/flutter/packages/main/packages/flutter_lints/lib/flutter.yaml'); + +Future> _fetchRulesFromGitHub(String optionsPath) async { + var optionsUrl = Uri.https('raw.githubusercontent.com', optionsPath); + var req = await http.get(optionsUrl); + var config = processAnalysisOptionsFile(req.body); + if (config == null) { + printToConsole('No config found for: $optionsUrl (SKIPPED)'); + return []; + } + return config.ruleConfigs.map((r) => r.name).nonNulls.toList(growable: false); +} diff --git a/pkg/linter/tool/machine.dart b/pkg/linter/tool/machine.dart index 6715c09650d..490cefc91ea 100644 --- a/pkg/linter/tool/machine.dart +++ b/pkg/linter/tool/machine.dart @@ -8,6 +8,7 @@ import 'dart:io'; import 'package:analyzer/src/lint/registry.dart'; import 'package:analyzer/src/lint/state.dart'; import 'package:args/args.dart'; +import 'package:collection/collection.dart'; import 'package:linter/src/analyzer.dart'; import 'package:linter/src/rules.dart'; import 'package:linter/src/utils.dart'; @@ -15,21 +16,18 @@ import 'package:yaml/yaml.dart'; import '../tool/util/path_utils.dart'; import 'messages_info.dart'; -import 'util/score_utils.dart' as score_utils; -/// Generates a list of lint rules in machine format suitable for consumption by -/// other tools. +/// Generates a list of built-in lint rules in JSON suitable for +/// consumption by other tools. +/// +/// **Deprecated:** This tool and the resulting generated file in +/// `tool/machine/rules.json` are deprecated and should not be relied on. void main(List args) async { var parser = ArgParser() - ..addFlag('write', abbr: 'w', help: 'Write `rules.json` file.') - ..addFlag('pretty', - abbr: 'p', help: 'Pretty-print output.', defaultsTo: true) - ..addFlag('sets', abbr: 's', help: 'Include rule sets', defaultsTo: true); + ..addFlag('write', abbr: 'w', help: 'Write `rules.json` file.'); var options = parser.parse(args); - var json = await generateRulesJson( - pretty: options['pretty'] == true, - includeSetInfo: options['sets'] == true); + var json = await generateRulesJson(); if (options['write'] == true) { var outFile = machineJsonFile(); @@ -40,48 +38,31 @@ void main(List args) async { } } -Future generateRulesJson({ - bool pretty = true, - bool includeSetInfo = true, -}) async { +Future generateRulesJson() async { registerLintRules(); var fixStatusMap = readFixStatusMap(); return await getMachineListing(Registry.ruleRegistry, - fixStatusMap: fixStatusMap, pretty: pretty); + fixStatusMap: fixStatusMap); } Future getMachineListing( Iterable ruleRegistry, { - Map? fixStatusMap, - bool pretty = true, - bool includeSetInfo = true, + Map fixStatusMap = const {}, }) async { - var rules = List.of(ruleRegistry, growable: false) - ..sort((a, b) => a.name.compareTo(b.name)); - var encoder = pretty ? JsonEncoder.withIndent(' ') : JsonEncoder(); - fixStatusMap ??= {}; + var rulesToDocument = List.of(ruleRegistry, growable: false) + .where((rule) => !rule.state.isInternal) + .sortedBy((rule) => rule.name); - var ( - coreRules: coreRules, - recommendedRules: recommendedRules, - flutterRules: flutterRules - ) = await _fetchSetRules(fetch: includeSetInfo); - - var json = encoder.convert([ - for (var (rule, info) in rules - .where((rule) => !rule.state.isInternal) - .map((rule) => (rule, messagesRuleInfo[rule.name]!))) + var json = JsonEncoder.withIndent(' ').convert([ + for (var (rule, info) + in rulesToDocument.map((rule) => (rule, messagesRuleInfo[rule.name]!))) { 'name': rule.name, 'description': rule.description, 'categories': info.categories.toList(growable: false), 'state': rule.state.label, 'incompatible': rule.incompatibleRules, - 'sets': [ - if (coreRules.contains(rule.name)) 'core', - if (recommendedRules.contains(rule.name)) 'recommended', - if (flutterRules.contains(rule.name)) 'flutter', - ], + 'sets': const [], 'fixStatus': fixStatusMap[rule.lintCodes.first.uniqueName] ?? 'unregistered', 'details': info.deprecatedDetails, @@ -113,28 +94,3 @@ Map readFixStatusMap() { if (code.startsWith('LintCode.')) code: value['status'] as String, }; } - -Future< - ({ - Set coreRules, - Set recommendedRules, - Set flutterRules, - })> _fetchSetRules({bool fetch = true}) async { - if (!fetch) { - return const ( - coreRules: {}, - recommendedRules: {}, - flutterRules: {}, - ); - } - - var coreRules = {...await score_utils.coreRules}; - var recommendedRules = {...coreRules, ...await score_utils.recommendedRules}; - var flutterRules = {...recommendedRules, ...await score_utils.flutterRules}; - - return ( - coreRules: coreRules, - recommendedRules: recommendedRules, - flutterRules: flutterRules, - ); -} diff --git a/pkg/linter/tool/machine/README.md b/pkg/linter/tool/machine/README.md new file mode 100644 index 00000000000..387f7a2e120 --- /dev/null +++ b/pkg/linter/tool/machine/README.md @@ -0,0 +1,34 @@ +# Generated inter rule information + +> [!WARNING] +> The `rules.json` file is unsupported and deprecated, +> and should **not** be relied on. + +The [`rules.json`](rules.json) is generated from lint information in +the rule source files as well as the `pkg/linter/messages.yaml` file. +It is primarily used by the `dart.dev` website. + +To update the `rules.json` file, run: + +``` +dart run pkg/linter/tool/machine/machine.dart -w +``` + +## Deprecation and replacement + +The `rules.json` file is unsupported and deprecated, +and should not be used nor should its contents be relied on. +In the future, it will stop receiving updates and +will be removed without notice. + +If you need a list of all available and stable lint rules, +you can reference [dart.dev/lints/all](https://dart.dev/lints/all). +[dart.dev/lints](https://dart.dev/lints) has details about each lint rule, +including deprecated, removed, and experimental rules. + +Some of the information in the `rules.json` file +is instead available in the `pkg/linter/messages.yaml` file. +However, the `messages.yaml` file is subject to change +and is not guaranteed to be stable. +To follow along and provide feedback on this transition, +check out [SDK issue #56835](https://github.com/dart-lang/sdk/issues/56835). diff --git a/pkg/linter/tool/machine/rules.json b/pkg/linter/tool/machine/rules.json index 0233c8aac58..c23579d7888 100644 --- a/pkg/linter/tool/machine/rules.json +++ b/pkg/linter/tool/machine/rules.json @@ -90,10 +90,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** annotate overridden methods and fields.\n\nThis practice improves code readability and helps protect against\nunintentionally overriding superclass members.\n\n**BAD:**\n```dart\nclass Cat {\n int get lives => 9;\n}\n\nclass Lucky extends Cat {\n final int lives = 14;\n}\n```\n\n**GOOD:**\n```dart\nabstract class Dog {\n String get breed;\n void bark() {}\n}\n\nclass Husky extends Dog {\n @override\n final String breed = 'Husky';\n @override\n void bark() {}\n}\n```", "sinceDartSdk": "2.0" @@ -228,11 +225,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** empty statements in the `else` clause of `if` statements.\n\n**BAD:**\n```dart\nif (x > y)\n print('1');\nelse ;\n print('2');\n```\n\nIf you want a statement that follows the empty clause to _conditionally_ run,\nremove the dangling semicolon to include it in the `else` clause.\nOptionally, also enclose the else's statement in a block.\n\n**GOOD:**\n```dart\nif (x > y)\n print('1');\nelse\n print('2');\n```\n\n**GOOD:**\n```dart\nif (x > y) {\n print('1');\n} else {\n print('2');\n}\n```\n\nIf you want a statement that follows the empty clause to _unconditionally_ run,\nremove the `else` clause.\n\n**GOOD:**\n```dart\nif (x > y) print('1');\n\nprint('2');\n```", "sinceDartSdk": "2.0" @@ -300,10 +293,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** using `forEach` with a function literal.\n\nThe `for` loop enables a developer to be clear and explicit as to their intent.\nA return in the body of the `for` loop returns from the body of the function,\nwhere as a return in the body of the `forEach` closure only returns a value\nfor that iteration of the `forEach`. The body of a `for` loop can contain\n`await`s, while the closure body of a `forEach` cannot.\n\n**BAD:**\n```dart\npeople.forEach((person) {\n ...\n});\n```\n\n**GOOD:**\n```dart\nfor (var person in people) {\n ...\n}\n```", "sinceDartSdk": "2.0" @@ -312,7 +302,8 @@ "name": "avoid_futureor_void", "description": "Avoid using 'FutureOr' as the type of a result.", "categories": [ - "errorProne" + "errorProne", + "unintentional" ], "state": "experimental", "incompatible": [], @@ -344,10 +335,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#dont-explicitly-initialize-variables-to-null):\n\n**DON'T** explicitly initialize variables to `null`.\n\nIf a variable has a non-nullable type or is `final`,\nDart reports a compile error if you try to use it\nbefore it has been definitely initialized.\nIf the variable is nullable and not `const` or `final`,\nthen it is implicitly initialized to `null` for you.\nThere's no concept of \"uninitialized memory\" in Dart\nand no need to explicitly initialize a variable to `null` to be \"safe\".\nAdding `= null` is redundant and unneeded.\n\n**BAD:**\n```dart\nItem? bestDeal(List cart) {\n Item? bestItem = null;\n\n for (final item in cart) {\n if (bestItem == null || item.price < bestItem.price) {\n bestItem = item;\n }\n }\n\n return bestItem;\n}\n```\n\n**GOOD:**\n```dart\nItem? bestDeal(List cart) {\n Item? bestItem;\n\n for (final item in cart) {\n if (bestItem == null || item.price < bestItem.price) {\n bestItem = item;\n }\n }\n\n return bestItem;\n}\n```", "sinceDartSdk": "2.0" @@ -414,9 +402,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** avoid `print` calls in production code.\n\nFor production code, consider using a logging framework.\nIf you are using Flutter, you can use `debugPrint`\nor surround `print` calls with a check for `kDebugMode`\n\n**BAD:**\n```dart\nvoid f(int x) {\n print('debug: $x');\n ...\n}\n```\n\n\n**GOOD:**\n```dart\nvoid f(int x) {\n debugPrint('debug: $x');\n ...\n}\n```\n\n\n**GOOD:**\n```dart\nvoid f(int x) {\n log('log: $x');\n ...\n}\n```\n\n\n**GOOD:**\n```dart\nvoid f(int x) {\n if (kDebugMode) {\n print('debug: $x');\n }\n ...\n}\n```", "sinceDartSdk": "2.5" @@ -456,11 +442,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** avoid relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. An easy way to avoid\nthat is to ensure you have no relative imports that include `lib/` in their\npaths.\n\nYou can also use 'always_use_package_imports' to disallow relative imports\nbetween files within `lib/`.\n\n**BAD:**\n```dart\nimport 'package:foo/bar.dart';\n\nimport '../lib/baz.dart';\n\n...\n```\n\n**GOOD:**\n```dart\nimport 'package:foo/bar.dart';\n\nimport 'baz.dart';\n\n...\n```", "sinceDartSdk": "2.0" @@ -473,10 +455,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** rename parameters of overridden methods.\n\nMethods that override another method, but do not have their own documentation\ncomment, will inherit the overridden method's comment when `dart doc` produces\ndocumentation. If the inherited method contains the name of the parameter (in\nsquare brackets), then `dart doc` cannot link it correctly.\n\n**BAD:**\n```dart\nabstract class A {\n m(a);\n}\n\nabstract class B extends A {\n m(b);\n}\n```\n\n**GOOD:**\n```dart\nabstract class A {\n m(a);\n}\n\nabstract class B extends A {\n m(a);\n}\n```", "sinceDartSdk": "2.0" @@ -490,10 +469,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** return types on setters.\n\nAs setters do not return a value, declaring the return type of one is redundant.\n\n**BAD:**\n```dart\nvoid set speed(int ms);\n```\n\n**GOOD:**\n```dart\nset speed(int ms);\n```", "sinceDartSdk": "2.0" @@ -528,10 +504,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** returning `null` for `void`.\n\nIn a large variety of languages `void` as return type is used to indicate that\na function doesn't return anything. Dart allows returning `null` in functions\nwith `void` return type but it also allow using `return;` without specifying any\nvalue. To have a consistent way you should not return `null` and only use an\nempty return.\n\n**BAD:**\n```dart\nvoid f1() {\n return null;\n}\nFuture f2() async {\n return null;\n}\n```\n\n**GOOD:**\n```dart\nvoid f1() {\n return;\n}\nFuture f2() async {\n return;\n}\n```", "sinceDartSdk": "2.1" @@ -571,11 +544,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**AVOID** shadowing type parameters.\n\n**BAD:**\n```dart\nclass A {\n void fn() {}\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n void fn() {}\n}\n```", "sinceDartSdk": "2.1" @@ -589,10 +558,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** single cascade in expression statements.\n\n**BAD:**\n```dart\no..m();\n```\n\n**GOOD:**\n```dart\no.m();\n```", "sinceDartSdk": "2.0" @@ -631,11 +597,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** using a parameter name that is the same as an existing type.\n\n**BAD:**\n```dart\nm(f(int));\n```\n\n**GOOD:**\n```dart\nm(f(int v));\n```", "sinceDartSdk": "2.0" @@ -664,9 +626,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** wrapping widgets in unnecessary containers.\n\nWrapping a widget in `Container` with no other parameters set has no effect\nand makes code needlessly more complex.\n\n**BAD:**\n```dart\nWidget buildRow() {\n return Container(\n child: Row(\n children: [\n const MyLogo(),\n const Expanded(\n child: Text('...'),\n ),\n ],\n )\n );\n}\n```\n\n**GOOD:**\n```dart\nWidget buildRow() {\n return Row(\n children: [\n const MyLogo(),\n const Expanded(\n child: Text('...'),\n ),\n ],\n );\n}\n```", "sinceDartSdk": "2.7" @@ -718,9 +678,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**AVOID** using web libraries, `dart:html`, `dart:js` and\n`dart:js_util` in Flutter packages that are not web plugins. These libraries are\nnot supported outside of a web context; functionality that depends on them will\nfail at runtime in Flutter mobile, and their use is generally discouraged in\nFlutter web.\n\nWeb library access *is* allowed in:\n\n* plugin packages that declare `web` as a supported context\n\notherwise, imports of `dart:html`, `dart:js` and `dart:js_util` are disallowed.", "sinceDartSdk": "2.6" @@ -733,11 +691,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** using await on anything which is not a future.\n\nAwait is allowed on the types: `Future`, `FutureOr`, `Future?`,\n`FutureOr?` and `dynamic`.\n\nFurther, using `await null` is specifically allowed as a way to introduce a\nmicrotask delay.\n\n**BAD:**\n```dart\nmain() async {\n print(await 23);\n}\n```\n\n**GOOD:**\n```dart\nmain() async {\n await null; // If a delay is really intended.\n print(23);\n}\n```", "sinceDartSdk": "2.0" @@ -751,11 +705,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/style#do-name-extensions-using-uppercamelcase):\n\n**DO** name extensions using `UpperCamelCase`.\n\nExtensions should capitalize the first letter of each word (including\nthe first word), and use no separators.\n\n**GOOD:**\n```dart\nextension MyFancyList on List { \n // ... \n}\n\nextension SmartIterable on Iterable {\n // ...\n}\n```", "sinceDartSdk": "2.6" @@ -769,11 +719,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/style#do-name-types-using-uppercamelcase):\n\n**DO** name types using UpperCamelCase.\n\nClasses and typedefs should capitalize the first letter of each word (including\nthe first word), and use no separators.\n\n**GOOD:**\n```dart\nclass SliderMenu {\n // ...\n}\n\nclass HttpRequest {\n // ...\n}\n\ntypedef num Adder(num x, num y);\n```", "sinceDartSdk": "2.0" @@ -842,11 +788,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** invoke certain collection method with an argument with an unrelated\ntype.\n\nDoing this will invoke `==` on the collection's elements and most likely will\nreturn `false`.\n\nAn argument passed to a collection method should relate to the collection type\nas follows:\n\n* an argument to `Iterable.contains` should be related to `E`\n* an argument to `List.remove` should be related to `E`\n* an argument to `Map.containsKey` should be related to `K`\n* an argument to `Map.containsValue` should be related to `V`\n* an argument to `Map.remove` should be related to `K`\n* an argument to `Map.[]` should be related to `K`\n* an argument to `Queue.remove` should be related to `E`\n* an argument to `Set.lookup` should be related to `E`\n* an argument to `Set.remove` should be related to `E`\n\n**BAD:**\n```dart\nvoid someFunction() {\n var list = [];\n if (list.contains('1')) print('someFunction'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction() {\n var set = {};\n set.remove('1'); // LINT\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction() {\n var list = [];\n if (list.contains(1)) print('someFunction'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction() {\n var set = {};\n set.remove(1); // OK\n}\n```", "sinceDartSdk": "2.19" @@ -898,10 +840,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** using lowerCamelCase for constant names.\n\nIn new code, use `lowerCamelCase` for constant variables, including enum values.\n\nIn existing code that uses `ALL_CAPS_WITH_UNDERSCORES` for constants, you may\ncontinue to use all caps to stay consistent.\n\n**BAD:**\n```dart\nconst PI = 3.14;\nconst kDefaultTimeout = 1000;\nfinal URL_SCHEME = RegExp('^([a-z]+):');\n\nclass Dice {\n static final NUMBER_GENERATOR = Random();\n}\n```\n\n**GOOD:**\n```dart\nconst pi = 3.14;\nconst defaultTimeout = 1000;\nfinal urlScheme = RegExp('^([a-z]+):');\n\nclass Dice {\n static final numberGenerator = Random();\n}\n```", "sinceDartSdk": "2.0" @@ -914,10 +853,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**AVOID** control flow leaving `finally` blocks.\n\nUsing control flow in `finally` blocks will inevitably cause unexpected behavior\nthat is hard to debug.\n\n**BAD:**\n```dart\nclass BadReturn {\n double nonCompliantMethod() {\n try {\n return 1 / 0;\n } catch (e) {\n print(e);\n } finally {\n return 1.0; // LINT\n }\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadContinue {\n double nonCompliantMethod() {\n for (var o in [1, 2]) {\n try {\n print(o / 0);\n } catch (e) {\n print(e);\n } finally {\n continue; // LINT\n }\n }\n return 1.0;\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadBreak {\n double nonCompliantMethod() {\n for (var o in [1, 2]) {\n try {\n print(o / 0);\n } catch (e) {\n print(e);\n } finally {\n break; // LINT\n }\n }\n return 1.0;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Ok {\n double compliantMethod() {\n var i = 5;\n try {\n i = 1 / 0;\n } catch (e) {\n print(e); // OK\n }\n return i;\n }\n}\n```", "sinceDartSdk": "2.0" @@ -930,11 +866,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** use curly braces for all flow control structures.\n\nDoing so avoids the [dangling else](https://en.wikipedia.org/wiki/Dangling_else)\nproblem.\n\n**BAD:**\n```dart\nif (overflowChars != other.overflowChars)\n return overflowChars < other.overflowChars;\n```\n\n**GOOD:**\n```dart\nif (isWeekDay) {\n print('Bike to work!');\n} else {\n print('Go dancing or read a book!');\n}\n```\n\nThere is one exception to this: an `if` statement with no `else` clause where\nthe entire `if` statement (including the condition and the body) fits in one\nline. In that case, you may leave off the braces if you prefer:\n\n**GOOD:**\n```dart\nif (arg == null) return defaultValue;\n```\n\nIf the body wraps to the next line, though, use braces:\n\n**GOOD:**\n```dart\nif (overflowChars != other.overflowChars) {\n return overflowChars < other.overflowChars;\n}\n```", "sinceDartSdk": "2.0" @@ -947,11 +879,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Attach library doc comments (with `///`) to library directives, rather than\nleaving them dangling near the top of a library.\n\n**BAD:**\n```dart\n/// This is a great library.\nimport 'package:math';\n```\n\n```dart\n/// This is a great library.\n\nclass C {}\n```\n\n**GOOD:**\n```dart\n/// This is a great library.\nlibrary;\n\nimport 'package:math';\n\nclass C {}\n```\n\n**NOTE:** An unnamed library, like `library;` above, is only supported in Dart\n2.19 and later. Code which might run in earlier versions of Dart will need to\nprovide a name in the `library` directive.", "sinceDartSdk": "2.19" @@ -964,11 +892,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "needsFix", "details": "**DO** depend on referenced packages.\n\nWhen importing a package, add a dependency on it to your pubspec.\n\nDepending explicitly on packages that you reference ensures they will always\nexist and allows you to put a dependency constraint on them to guard you\nagainst breaking changes.\n\nWhether this should be a regular dependency or dev_dependency depends on if it\nis referenced from a public file (one under either `lib` or `bin`), or some\nother private file.\n\n**BAD:**\n```dart\nimport 'package:a/a.dart';\n```\n\n```yaml\ndependencies:\n```\n\n**GOOD:**\n```dart\nimport 'package:a/a.dart';\n```\n\n```yaml\ndependencies:\n a: ^1.0.0\n```", "sinceDartSdk": "2.14" @@ -1073,11 +997,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** empty catch blocks.\n\nIn general, empty catch blocks should be avoided. In cases where they are\nintended, a comment should be provided to explain why exceptions are being\ncaught and suppressed. Alternatively, the exception identifier can be named with\nunderscores (e.g., `_`) to indicate that we intend to skip it.\n\n**BAD:**\n```dart\ntry {\n ...\n} catch(exception) { }\n```\n\n**GOOD:**\n```dart\ntry {\n ...\n} catch(e) {\n // ignored, really.\n}\n\n// Alternatively:\ntry {\n ...\n} catch(_) { }\n\n// Better still:\ntry {\n ...\n} catch(e) {\n doSomething(e);\n}\n```", "sinceDartSdk": "2.0" @@ -1092,10 +1012,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#do-use--instead-of--for-empty-constructor-bodies):\n\n**DO** use `;` instead of `{}` for empty constructor bodies.\n\nIn Dart, a constructor with an empty body can be terminated with just a\nsemicolon. This is required for const constructors. For consistency and\nbrevity, other constructors should also do this.\n\n**BAD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y) {}\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y);\n}\n```", "sinceDartSdk": "2.0" @@ -1108,10 +1025,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** empty statements.\n\nEmpty statements almost always indicate a bug.\n\nFor example,\n\n**BAD:**\n```dart\nif (complicated.expression.foo());\n bar();\n```\n\nFormatted with `dart format` the bug becomes obvious:\n\n```dart\nif (complicated.expression.foo()) ;\nbar();\n\n```\n\nBetter to avoid the empty statement altogether.\n\n**GOOD:**\n```dart\nif (complicated.expression.foo())\n bar();\n```", "sinceDartSdk": "2.0" @@ -1148,10 +1062,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Switching on instances of enum-like classes should be exhaustive.\n\nEnum-like classes are defined as concrete (non-abstract) classes that have:\n * only private non-factory constructors\n * two or more static const fields whose type is the enclosing class and\n * no subclasses of the class in the defining library\n\n**DO** define case clauses for all constants in enum-like classes.\n\n**BAD:**\n```dart\nclass EnumLike {\n final int i;\n const EnumLike._(this.i);\n\n static const e = EnumLike._(1);\n static const f = EnumLike._(2);\n static const g = EnumLike._(3);\n}\n\nvoid bad(EnumLike e) {\n // Missing case.\n switch(e) { // LINT\n case EnumLike.e :\n print('e');\n break;\n case EnumLike.f :\n print('f');\n break;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass EnumLike {\n final int i;\n const EnumLike._(this.i);\n\n static const e = EnumLike._(1);\n static const f = EnumLike._(2);\n static const g = EnumLike._(3);\n}\n\nvoid ok(EnumLike e) {\n // All cases covered.\n switch(e) { // OK\n case EnumLike.e :\n print('e');\n break;\n case EnumLike.f :\n print('f');\n break;\n case EnumLike.g :\n print('g');\n break;\n }\n}\n```", "sinceDartSdk": "2.9" @@ -1164,11 +1075,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DO** name source files using `lowercase_with_underscores`.\n\nSome file systems are not case-sensitive, so many projects require filenames to\nbe all lowercase. Using a separating character allows names to still be readable\nin that form. Using underscores as the separator ensures that the name is still\na valid Dart identifier, which may be helpful if the language later supports\nsymbolic imports.\n\n**BAD:**\n\n* `SliderMenu.dart`\n* `filesystem.dart`\n* `file-system.dart`\n\n**GOOD:**\n\n* `slider_menu.dart`\n* `file_system.dart`\n\nFiles without a strict `.dart` extension are ignored. For example:\n\n**OK:**\n\n* `file-system.g.dart`\n* `SliderMenu.css.dart`\n\nThe lint `library_names` can be used to enforce the same kind of naming on the\nlibrary.", "sinceDartSdk": "2.0" @@ -1194,11 +1101,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** override `hashCode` if overriding `==` and prefer overriding `==` if\noverriding `hashCode`.\n\nEvery object in Dart has a `hashCode`. Both the `==` operator and the\n`hashCode` property of objects must be consistent in order for a common hash\nmap implementation to function properly. Thus, when overriding `==`, the\n`hashCode` should also be overridden to maintain consistency. Similarly, if\n`hashCode` is overridden, `==` should be also.\n\n**BAD:**\n```dart\nclass Bad {\n final int value;\n Bad(this.value);\n\n @override\n bool operator ==(Object other) => other is Bad && other.value == value;\n}\n```\n\n**GOOD:**\n```dart\nclass Better {\n final int value;\n Better(this.value);\n\n @override\n bool operator ==(Object other) =>\n other is Better &&\n other.runtimeType == runtimeType &&\n other.value == value;\n\n @override\n int get hashCode => value.hashCode;\n}\n```", "sinceDartSdk": "2.0" @@ -1211,10 +1114,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "From the the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files):\n\n**DON'T** import implementation files from another package.\n\nThe libraries inside `lib` are publicly visible: other packages are free to\nimport them. But much of a package's code is internal implementation libraries\nthat should only be imported and used by the package itself. Those go inside a\nsubdirectory of `lib` called `src`. You can create subdirectories in there if\nit helps you organize things.\n\nYou are free to import libraries that live in `lib/src` from within other Dart\ncode in the same package (like other libraries in `lib`, scripts in `bin`,\nand tests) but you should never import from another package's `lib/src`\ndirectory. Those files are not part of the package's public API, and they\nmight change in ways that could break your code.\n\n**BAD:**\n```dart\n// In 'road_runner'\nimport 'package:acme/src/internals.dart';\n```", "sinceDartSdk": "2.0" @@ -1227,11 +1127,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO**\nExplicitly tear off `.call` methods from objects when assigning to a Function\ntype. There is less magic with an explicit tear off. Future language versions\nmay remove the implicit call tear off.\n\n**BAD:**\n```dart\nclass Callable {\n void call() {}\n}\nvoid callIt(void Function() f) {\n f();\n}\n\ncallIt(Callable());\n```\n\n**GOOD:**\n```dart\nclass Callable {\n void call() {}\n}\nvoid callIt(void Function() f) {\n f();\n}\n\ncallIt(Callable().call);\n```", "sinceDartSdk": "2.19" @@ -1271,10 +1167,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "needsEvaluation", "details": "**DON'T** use `is` checks where the type is a JS interop type.\n\n**DON'T** use `is` checks where the type is a generic Dart type that has JS\ninterop type arguments.\n\n**DON'T** use `is` checks with a JS interop value.\n\n`dart:js_interop` types have runtime types that are different based on whether\nyou are compiling to JS or to Wasm. Therefore, runtime type checks may result in\ndifferent behavior. Runtime checks also do not necessarily check that a JS\ninterop value is a particular JavaScript type.\n\n**BAD:**\n```dart\nextension type HTMLElement(JSObject o) {}\nextension type HTMLDivElement(JSObject o) implements HTMLElement {}\n\nvoid compute(JSAny a, bool b, List lo, List ls, JSObject o,\n HTMLElement e) {\n a is String; // LINT, checking that a JS value is a Dart type\n b is JSBoolean; // LINT, checking that a Dart value is a JS type\n a is JSString; // LINT, checking that a JS value is a different JS interop\n // type\n o is JSNumber; // LINT, checking that a JS value is a different JS interop\n // type\n lo is List; // LINT, JS interop type argument and Dart type argument\n // are incompatible\n ls is List; // LINT, Dart type argument and JS interop type argument\n // are incompatible\n lo is List; // LINT, comparing JS interop type argument with\n // different JS interop type argument\n lo is List; // LINT, comparing JS interop type argument with\n // different JS interop type argument\n o is HTMLElement; // LINT, true because both are JSObjects but doesn't check\n // that it's a JS HTMLElement\n e is HTMLDivElement; // LINT, true because both are JSObjects but doesn't\n // check that it's a JS HTMLDivElement\n}\n```\n\nPrefer using JS interop helpers like `isA` from `dart:js_interop` to check the\nunderlying type of JS interop values.\n\n**GOOD:**\n```dart\nextension type HTMLElement(JSObject o) implements JSObject {}\nextension type HTMLDivElement(JSObject o) implements HTMLElement {}\n\nvoid compute(JSAny a, List l, JSObject o, HTMLElement e) {\n a.isA; // OK, uses JS interop to check it is a JS string\n l[0].isA; // OK, uses JS interop to check it is a JS string\n o.isA(); // OK, uses JS interop to check `o` is an HTMLElement\n e.isA(); // OK, uses JS interop to check `e` is an\n // HTMLDivElement\n}\n```\n\n**DON'T** use `as` to cast a JS interop value to an unrelated Dart type or an\nunrelated Dart value to a JS interop type.\n\n**DON'T** use `as` to cast a JS interop value to a JS interop type represented\nby an incompatible `dart:js_interop` type.\n\n**BAD:**\n```dart\nextension type Window(JSObject o) {}\n\nvoid compute(String s, JSBoolean b, Window w, List l,\n List lo) {\n s as JSString; // LINT, casting Dart type to JS interop type\n b as bool; // LINT, casting JS interop type to Dart type\n b as JSNumber; // LINT, JSBoolean and JSNumber are incompatible\n b as Window; // LINT, JSBoolean and JSObject are incompatible\n w as JSBoolean; // LINT, JSObject and JSBoolean are incompatible\n l as List; // LINT, casting Dart value with Dart type argument to\n // Dart type with JS interop type argument\n lo as List; // LINT, casting Dart value with JS interop type argument\n // to Dart type with Dart type argument\n lo as List; // LINT, casting Dart value with JS interop type\n // argument to Dart type with incompatible JS interop\n // type argument\n}\n```\n\nPrefer using `dart:js_interop` conversion methods to convert a JS interop value\nto a Dart value and vice versa.\n\n**GOOD:**\n```dart\nextension type Window(JSObject o) {}\nextension type Document(JSObject o) {}\n\nvoid compute(String s, JSBoolean b, Window w, JSArray a,\n List ls, JSObject o, List la) {\n s.toJS; // OK, converts the Dart type to a JS type\n b.toDart; // OK, converts the JS type to a Dart type\n a.toDart; // OK, converts the JS type to a Dart type\n w as Document; // OK, but no runtime check that `w` is a JS Document\n ls.map((e) => e.toJS).toList(); // OK, converts the Dart types to JS types\n o as JSArray; // OK, JSObject and JSArray are compatible\n la as List; // OK, JSAny and JSString are compatible\n (o as Object) as JSObject; // OK, Object is a supertype of JSAny\n}\n```", "sinceDartSdk": "3.5" @@ -1336,11 +1229,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Attach library annotations to library directives, rather than\nsome other library-level element.\n\n**BAD:**\n```dart\n@TestOn('browser')\n\nimport 'package:test/test.dart';\n\nvoid main() {}\n```\n\n**GOOD:**\n```dart\n@TestOn('browser')\nlibrary;\n\nimport 'package:test/test.dart';\n\nvoid main() {}\n```\n\n**NOTE:** An unnamed library, like `library;` above, is only supported in Dart\n2.19 and later. Code which might run in earlier versions of Dart will need to\nprovide a name in the `library` directive.", "sinceDartSdk": "2.19" @@ -1366,10 +1255,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DO** use `lowercase_with_underscores` when specifying a library prefix.\n\n**BAD:**\n```dart\nimport 'dart:math' as Math;\nimport 'dart:json' as JSON;\nimport 'package:js/js.dart' as JS;\nimport 'package:javascript_utils/javascript_utils.dart' as jsUtils;\n```\n\n**GOOD:**\n```dart\nimport 'dart:math' as math;\nimport 'dart:json' as json;\nimport 'package:js/js.dart' as js;\nimport 'package:javascript_utils/javascript_utils.dart' as js_utils;\n```", "sinceDartSdk": "2.0" @@ -1382,10 +1268,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**AVOID** using library private types in public APIs.\n\nFor the purposes of this lint, a public API is considered to be any top-level or\nmember declaration unless the declaration is library private or contained in a\ndeclaration that's library private. The following uses of types are checked:\n\n- the return type of a function or method,\n- the type of any parameter of a function or method,\n- the bound of a type parameter to any function, method, class, mixin,\n extension's extended type, or type alias,\n- the type of any top level variable or field,\n- any type used in the declaration of a type alias (for example\n `typedef F = _Private Function();`), or\n- any type used in the `on` clause of an extension or a mixin\n\n**BAD:**\n```dart\nf(_Private p) { ... }\nclass _Private {}\n```\n\n**GOOD:**\n```dart\nf(String s) { ... }\n```", "sinceDartSdk": "2.14" @@ -1500,11 +1383,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use more than one case with same value.\n\nThis is usually a typo or changed value of constant.\n\n**BAD:**\n```dart\nconst int A = 1;\nswitch (v) {\n case 1:\n case 2:\n case A:\n case 2:\n}\n```\n\n**GOOD:**\n```dart\nconst int A = 1;\nswitch (v) {\n case A:\n case 2:\n}\n```\n\nNOTE: this lint only reports duplicate cases in libraries opted in to Dart 2.19\nand below. In Dart 3.0 and after, duplicate cases are reported as dead code\nby the analyzer.", "sinceDartSdk": "2.0" @@ -1517,10 +1396,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use a leading underscore for library prefixes.\nThere is no concept of \"private\" for library prefixes. When one of those has a\nname that starts with an underscore, it sends a confusing signal to the reader.\nTo avoid that, don't use leading underscores in those names.\n\n**BAD:**\n```dart\nimport 'dart:core' as _core;\n```\n\n**GOOD:**\n```dart\nimport 'dart:core' as core;\n```", "sinceDartSdk": "2.16" @@ -1533,10 +1409,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use a leading underscore for identifiers that aren't private. Dart\nuses a leading underscore in an identifier to mark members and top-level\ndeclarations as private. This trains users to associate a leading underscore\nwith one of those kinds of declarations. They see `_` and think \"private\".\nThere is no concept of \"private\" for local variables or parameters. When one of\nthose has a name that starts with an underscore, it sends a confusing signal to\nthe reader. To avoid that, don't use leading underscores in those names.\n\n**EXCEPTION:**: An unused parameter can be named `_`, `__`, `___`, etc. This is\ncommon practice in callbacks where you are passed a value but you don't need\nto use it. Giving it a name that consists solely of underscores is the idiomatic\nway to indicate that the value isn't used.\n\n**BAD:**\n```dart\nvoid print(String _name) {\n var _size = _name.length;\n ...\n}\n```\n**GOOD:**\n\n```dart\nvoid print(String name) {\n var size = name.length;\n ...\n}\n```\n\n**OK:**\n\n```dart\n[1,2,3].map((_) => print('Hello'));\n```", "sinceDartSdk": "2.16" @@ -1564,9 +1437,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** put any logic in `createState()`.\n\nImplementations of `createState()` should return a new instance\nof a State object and do nothing more. Since state access is preferred\nvia the `widget` field, passing data to `State` objects using custom\nconstructor parameters should also be avoided and so further, the State\nconstructor is required to be passed no arguments.\n\n**BAD:**\n```dart\nMyState global;\n\nclass MyStateful extends StatefulWidget {\n @override\n MyState createState() {\n global = MyState();\n return global;\n }\n}\n```\n\n```dart\nclass MyStateful extends StatefulWidget {\n @override\n MyState createState() => MyState()..field = 42;\n}\n```\n\n```dart\nclass MyStateful extends StatefulWidget {\n @override\n MyState createState() => MyState(42);\n}\n```\n\n\n**GOOD:**\n```dart\nclass MyStateful extends StatefulWidget {\n @override\n MyState createState() {\n return MyState();\n }\n}\n```", "sinceDartSdk": "2.8" @@ -1606,11 +1477,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "needsEvaluation", "details": "**DON'T** use wildcard parameters or variables.\n\nWildcard parameters and local variables\n(e.g. underscore-only names like `_`, `__`, `___`, etc.) will\nbecome non-binding in a future version of the Dart language.\nAny existing code that uses wildcard parameters or variables will\nbreak. In anticipation of this change, and to make adoption easier,\nthis lint disallows wildcard and variable parameter uses.\n\n\n**BAD:**\n```dart\nvar _ = 1;\nprint(_); // LINT\n```\n\n```dart\nvoid f(int __) {\n print(__); // LINT multiple underscores too\n}\n```\n\n**GOOD:**\n```dart\nfor (var _ in [1, 2, 3]) count++;\n```\n\n```dart\nvar [a, _, b, _] = [1, 2, 3, 4];\n```", "sinceDartSdk": "3.1" @@ -1623,11 +1490,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** name non-constant identifiers using lowerCamelCase.\n\nClass members, top-level definitions, variables, parameters, named parameters\nand named constructors should capitalize the first letter of each word\nexcept the first word, and use no separators.\n\n**GOOD:**\n```dart\nvar item;\n\nHttpRequest httpRequest;\n\nalign(clearItems) {\n // ...\n}\n```", "sinceDartSdk": "2.0" @@ -1653,11 +1516,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use `null` check on a potentially nullable type parameter.\n\nGiven a generic type parameter `T` which has a nullable bound (e.g., the default\nbound of `Object?`), it is very easy to introduce erroneous `null` checks when\nworking with a variable of type `T?`. Specifically, it is not uncommon to have\n`T? x;` and want to assert that `x` has been set to a valid value of type `T`.\nA common mistake is to do so using `x!`. This is almost always incorrect, since\nif `T` is a nullable type, `x` may validly hold `null` as a value of type `T`.\n\n**BAD:**\n```dart\nT run(T callback()) {\n T? result;\n (() { result = callback(); })();\n return result!;\n}\n```\n\n**GOOD:**\n```dart\nT run(T callback()) {\n T? result;\n (() { result = callback(); })();\n return result as T;\n}\n```", "sinceDartSdk": "2.12" @@ -1670,10 +1529,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** pass `null` as an argument where a closure is expected.\n\nOften a closure that is passed to a method will only be called conditionally,\nso that tests and \"happy path\" production calls do not reveal that `null` will\nresult in an exception being thrown.\n\nThis rule only catches null literals being passed where closures are expected\nin the following locations:\n\n#### Constructors\n\n* From `dart:async`\n * `Future` at the 0th positional parameter\n * `Future.microtask` at the 0th positional parameter\n * `Future.sync` at the 0th positional parameter\n * `Timer` at the 0th positional parameter\n * `Timer.periodic` at the 1st positional parameter\n* From `dart:core`\n * `List.generate` at the 1st positional parameter\n\n#### Static functions\n\n* From `dart:async`\n * `scheduleMicrotask` at the 0th positional parameter\n * `Future.doWhile` at the 0th positional parameter\n * `Future.forEach` at the 0th positional parameter\n * `Future.wait` at the named parameter `cleanup`\n * `Timer.run` at the 0th positional parameter\n\n#### Instance methods\n\n* From `dart:async`\n * `Future.then` at the 0th positional parameter\n * `Future.complete` at the 0th positional parameter\n* From `dart:collection`\n * `Queue.removeWhere` at the 0th positional parameter\n * `Queue.retain\n * `Iterable.firstWhere` at the 0th positional parameter, and the named\n parameter `orElse`\n * `Iterable.forEach` at the 0th positional parameter\n * `Iterable.fold` at the 1st positional parameter\n * `Iterable.lastWhere` at the 0th positional parameter, and the named\n parameter `orElse`\n * `Iterable.map` at the 0th positional parameter\n * `Iterable.reduce` at the 0th positional parameter\n * `Iterable.singleWhere` at the 0th positional parameter, and the named\n parameter `orElse`\n * `Iterable.skipWhile` at the 0th positional parameter\n * `Iterable.takeWhile` at the 0th positional parameter\n * `Iterable.where` at the 0th positional parameter\n * `List.removeWhere` at the 0th positional parameter\n * `List.retainWhere` at the 0th positional parameter\n * `String.replaceAllMapped` at the 1st positional parameter\n * `String.replaceFirstMapped` at the 1st positional parameter\n * `String.splitMapJoin` at the named parameters `onMatch` and `onNonMatch`\n\n**BAD:**\n```dart\n[1, 3, 5].firstWhere((e) => e.isOdd, orElse: null);\n```\n\n**GOOD:**\n```dart\n[1, 3, 5].firstWhere((e) => e.isOdd, orElse: () => null);\n```", "sinceDartSdk": "2.0" @@ -1745,10 +1601,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** override fields.\n\nOverriding fields is almost always done unintentionally. Regardless, it is a\nbad practice to do so.\n\n**BAD:**\n```dart\nclass Base {\n Object field = 'lorem';\n\n Object something = 'change';\n}\n\nclass Bad1 extends Base {\n @override\n final field = 'ipsum'; // LINT\n}\n\nclass Bad2 extends Base {\n @override\n Object something = 'done'; // LINT\n}\n```\n\n**GOOD:**\n```dart\nclass Base {\n Object field = 'lorem';\n\n Object something = 'change';\n}\n\nclass Ok extends Base {\n Object newField; // OK\n\n final Object newFinal = 'ignore'; // OK\n}\n```\n\n**GOOD:**\n```dart\nabstract class BaseLoggingHandler {\n Base transformer;\n}\n\nclass LogPrintHandler implements BaseLoggingHandler {\n @override\n Derived transformer; // OK\n}\n```", "sinceDartSdk": "2.0" @@ -1775,10 +1628,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "From the [Pubspec format description](https://dart.dev/tools/pub/pubspec):\n\n**DO** use `lowercase_with_underscores` for package names.\n\nPackage names should be all lowercase, with underscores to separate words,\n`just_like_this`. Use only basic Latin letters and Arabic digits: \\[a-z0-9\\_\\].\nAlso, make sure the name is a valid Dart identifier -- that it doesn't start\nwith digits and isn't a reserved word.", "sinceDartSdk": "2.0" @@ -1817,10 +1667,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** use adjacent strings to concatenate string literals.\n\n**BAD:**\n```dart\nraiseAlarm(\n 'ERROR: Parts of the spaceship are on fire. Other ' +\n 'parts are overrun by martians. Unclear which are which.');\n```\n\n**GOOD:**\n```dart\nraiseAlarm(\n 'ERROR: Parts of the spaceship are on fire. Other '\n 'parts are overrun by martians. Unclear which are which.');\n```", "sinceDartSdk": "2.0" @@ -1871,10 +1718,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** use collection literals when possible.\n\n**BAD:**\n```dart\nvar addresses = Map();\nvar uniqueNames = Set();\nvar ids = LinkedHashSet();\nvar coordinates = LinkedHashMap();\n```\n\n**GOOD:**\n```dart\nvar addresses = {};\nvar uniqueNames = {};\nvar ids = {};\nvar coordinates = {};\n```\n\n**EXCEPTIONS:**\n\nWhen a `LinkedHashSet` or `LinkedHashMap` is expected, a collection literal is\nnot preferred (or allowed).\n\n```dart\nvoid main() {\n LinkedHashSet linkedHashSet = LinkedHashSet.from([1, 2, 3]); // OK\n LinkedHashMap linkedHashMap = LinkedHashMap(); // OK\n\n printSet(LinkedHashSet()); // LINT\n printHashSet(LinkedHashSet()); // OK\n\n printMap(LinkedHashMap()); // LINT\n printHashMap(LinkedHashMap()); // OK\n}\n\nvoid printSet(Set ids) => print('$ids!');\nvoid printHashSet(LinkedHashSet ids) => printSet(ids);\nvoid printMap(Map map) => print('$map!');\nvoid printHashMap(LinkedHashMap map) => printMap(map);\n```", "sinceDartSdk": "2.0" @@ -1888,10 +1732,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** using `??=` over testing for `null`.\n\nAs Dart has the `??=` operator, it is advisable to use it where applicable to\nimprove the brevity of your code.\n\n**BAD:**\n```dart\nString get fullName {\n if (_fullName == null) {\n _fullName = getFullUserName(this);\n }\n return _fullName;\n}\n```\n\n**GOOD:**\n```dart\nString get fullName {\n return _fullName ??= getFullUserName(this);\n}\n```", "sinceDartSdk": "2.0" @@ -1917,9 +1758,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** declaring `const` constructors on `@immutable` classes.\n\nIf a class is immutable, it is usually a good idea to make its constructor a\n`const` constructor.\n\n**BAD:**\n```dart\n@immutable\nclass A {\n final a;\n A(this.a);\n}\n```\n\n**GOOD:**\n```dart\n@immutable\nclass A {\n final a;\n const A(this.a);\n}\n```", "sinceDartSdk": "2.0" @@ -1971,10 +1810,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use `indexOf` to see if a collection contains an element.\n\nCalling `indexOf` to see if a collection contains something is difficult to read\nand may have poor performance.\n\nInstead, prefer `contains`.\n\n**BAD:**\n```dart\nif (lunchBox.indexOf('sandwich') == -1) return 'so hungry...';\n```\n\n**GOOD:**\n```dart\nif (!lunchBox.contains('sandwich')) return 'so hungry...';\n```", "sinceDartSdk": "2.0" @@ -2028,10 +1864,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/design#prefer-making-fields-and-top-level-variables-final):\n\n**DO** prefer declaring private fields as `final` if they are not reassigned\nlater in the library.\n\nDeclaring fields as `final` when possible is a good practice because it helps\navoid accidental reassignments and allows the compiler to do optimizations.\n\n**BAD:**\n```dart\nclass BadImmutable {\n var _label = 'hola mundo! BadImmutable'; // LINT\n var label = 'hola mundo! BadImmutable'; // OK\n}\n```\n\n**BAD:**\n```dart\nclass MultipleMutable {\n var _label = 'hola mundo! GoodMutable', _offender = 'mumble mumble!'; // LINT\n var _someOther; // LINT\n\n MultipleMutable() : _someOther = 5;\n\n MultipleMutable(this._someOther);\n\n void changeLabel() {\n _label= 'hello world! GoodMutable';\n }\n}\n```\n\n**GOOD:**\n```dart\nclass GoodImmutable {\n final label = 'hola mundo! BadImmutable', bla = 5; // OK\n final _label = 'hola mundo! BadImmutable', _bla = 5; // OK\n}\n```\n\n**GOOD:**\n```dart\nclass GoodMutable {\n var _label = 'hola mundo! GoodMutable';\n\n void changeLabel() {\n _label = 'hello world! GoodMutable';\n }\n}\n```\n\n**BAD:**\n```dart\nclass AssignedInAllConstructors {\n var _label; // LINT\n AssignedInAllConstructors(this._label);\n AssignedInAllConstructors.withDefault() : _label = 'Hello';\n}\n```\n\n**GOOD:**\n```dart\nclass NotAssignedInAllConstructors {\n var _label; // OK\n NotAssignedInAllConstructors();\n NotAssignedInAllConstructors.withDefault() : _label = 'Hello';\n}\n```", "sinceDartSdk": "2.0" @@ -2089,10 +1922,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "When building maps from iterables, it is preferable to use `for` elements.\n\nUsing 'for' elements brings several benefits including:\n\n- Performance\n- Flexibility\n- Readability\n- Improved type inference\n- Improved interaction with null safety\n\n\n**BAD:**\n```dart\nMap.fromIterable(\n kAllGalleryDemos,\n key: (demo) => '${demo.routeName}',\n value: (demo) => demo.buildRoute,\n);\n```\n\n**GOOD:**\n```dart\nreturn {\n for (var demo in kAllGalleryDemos)\n '${demo.routeName}': demo.buildRoute,\n};\n```\n\n**GOOD:**\n```dart\n// Map is not required, type is inferred automatically.\nfinal pizzaRecipients = {\n ...studentLeaders,\n for (var student in classG)\n if (student.isPassing) student.id: student,\n};\n```", "sinceDartSdk": "2.3" @@ -2119,10 +1949,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-a-function-declaration-to-bind-a-function-to-a-name):\n\n**DO** use a function declaration to bind a function to a name.\n\nAs Dart allows local function declarations, it is a good practice to use them in\nthe place of function literals.\n\n**BAD:**\n```dart\nvoid main() {\n var localFunction = () {\n ...\n };\n}\n```\n\n**GOOD:**\n```dart\nvoid main() {\n localFunction() {\n ...\n }\n}\n```", "sinceDartSdk": "2.0" @@ -2135,11 +1962,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** generic function type aliases.\n\nWith the introduction of generic functions, function type aliases\n(`typedef void F()`) couldn't express all of the possible kinds of\nparameterization that users might want to express. Generic function type aliases\n(`typedef F = void Function()`) fixed that issue.\n\nFor consistency and readability reasons, it's better to only use one syntax and\nthus prefer generic function type aliases.\n\n**BAD:**\n```dart\ntypedef void F();\n```\n\n**GOOD:**\n```dart\ntypedef F = void Function();\n```", "sinceDartSdk": "2.0" @@ -2167,10 +1990,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** using `??` operators instead of `null` checks and conditional\nexpressions.\n\n**BAD:**\n```dart\nv = a == null ? b : a;\n```\n\n**GOOD:**\n```dart\nv = a ?? b;\n```", "sinceDartSdk": "2.4" @@ -2184,10 +2004,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** use initializing formals when possible.\n\nUsing initializing formals when possible makes your code more terse.\n\n**BAD:**\n```dart\nclass Point {\n num? x, y;\n Point(num x, num y) {\n this.x = x;\n this.y = y;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n num? x, y;\n Point(num this.x, num this.y);\n}\n```\n\n**BAD:**\n```dart\nclass Point {\n num? x, y;\n Point({num? x, num? y}) {\n this.x = x;\n this.y = y;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n num? x, y;\n Point({required num this.x, required num this.y});\n}\n```\n\n**NOTE:**\nThis rule will not generate a lint for named parameters unless the parameter\nname and the field name are the same. The reason for this is that resolving\nsuch a lint would require either renaming the field or renaming the parameter,\nand both of those actions would potentially be a breaking change. For example,\nthe following will not generate a lint:\n\n```dart\nclass Point {\n bool? isEnabled;\n Point({bool? enabled}) {\n this.isEnabled = enabled; // OK\n }\n}\n```\n\n**NOTE:**\nAlso note that it is possible to enforce a type that is stricter than the\ninitialized field with an initializing formal parameter. In the following\nexample the unnamed `Bid` constructor requires a non-null `int` despite\n`amount` being declared nullable (`int?`).\n\n```dart\nclass Bid {\n final int? amount;\n Bid(int this.amount);\n Bid.pass() : amount = null;\n}\n```", "sinceDartSdk": "2.0" @@ -2201,10 +2018,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Declare elements in list literals inline, rather than using `add` and\n`addAll` methods where possible.\n\n\n**BAD:**\n```dart\nvar l = ['a']..add('b')..add('c');\nvar l2 = ['a']..addAll(['b', 'c']);\n```\n\n**GOOD:**\n```dart\nvar l = ['a', 'b', 'c'];\nvar l2 = ['a', 'b', 'c'];\n```", "sinceDartSdk": "2.3" @@ -2230,10 +2044,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** using interpolation to compose strings and values.\n\nUsing interpolation when composing strings and values is usually easier to write\nand read than concatenation.\n\n**BAD:**\n```dart\n'Hello, ' + person.name + ' from ' + person.city + '.';\n```\n\n**GOOD:**\n```dart\n'Hello, ${person.name} from ${person.city}.'\n```", "sinceDartSdk": "2.0" @@ -2246,11 +2057,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use `length` to see if a collection is empty.\n\nThe `Iterable` contract does not require that a collection know its length or be\nable to provide it in constant time. Calling `length` just to see if the\ncollection contains anything can be painfully slow.\n\nInstead, there are faster and more readable getters: `isEmpty` and\n`isNotEmpty`. Use the one that doesn't require you to negate the result.\n\n**BAD:**\n```dart\nif (lunchBox.length == 0) return 'so hungry...';\nif (words.length != 0) return words.join(' ');\n```\n\n**GOOD:**\n```dart\nif (lunchBox.isEmpty) return 'so hungry...';\nif (words.isNotEmpty) return words.join(' ');\n```", "sinceDartSdk": "2.0" @@ -2263,11 +2070,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** `x.isNotEmpty` to `!x.isEmpty` for `Iterable` and `Map` instances.\n\nWhen testing whether an iterable or map is empty, prefer `isNotEmpty` over\n`!isEmpty` to improve code readability.\n\n**BAD:**\n```dart\nif (!sources.isEmpty) {\n process(sources);\n}\n```\n\n**GOOD:**\n```dart\nif (todo.isNotEmpty) {\n sendResults(request, todo.isEmpty);\n}\n```", "sinceDartSdk": "2.0" @@ -2281,10 +2084,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "When checking if an object is not of a specified type, it is preferable to use the 'is!' operator.\n\n**BAD:**\n```dart\nif (!(foo is Foo)) {\n ...\n}\n```\n\n**GOOD:**\n```dart\nif (foo is! Foo) {\n ...\n}\n```", "sinceDartSdk": "2.7" @@ -2297,11 +2097,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** `iterable.whereType()` over `iterable.where((e) => e is T)`.\n\n**BAD:**\n```dart\niterable.where((e) => e is MyClass);\n```\n\n**GOOD:**\n```dart\niterable.whereType();\n```", "sinceDartSdk": "2.0" @@ -2343,10 +2139,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** using `null`-aware operators instead of `null` checks in conditional\nexpressions.\n\n**BAD:**\n```dart\nv = a == null ? null : a.b;\n```\n\n**GOOD:**\n```dart\nv = a?.b;\n```", "sinceDartSdk": "2.2" @@ -2390,10 +2183,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Use spread collections when possible.\n\nCollection literals are excellent when you want to create a new collection out\nof individual items. But, when existing items are already stored in another\ncollection, spread collection syntax leads to simpler code.\n\n**BAD:**\n\n```dart\nWidget build(BuildContext context) {\n return CupertinoPageScaffold(\n child: ListView(\n children: [\n Tab2Header(),\n ]..addAll(buildTab2Conversation()),\n ),\n );\n}\n```\n\n```dart\nvar ints = [1, 2, 3];\nprint(['a']..addAll(ints.map((i) => i.toString()))..addAll(['c']));\n```\n\n```dart\nvar things;\nvar l = ['a']..addAll(things ?? const []);\n```\n\n\n**GOOD:**\n\n```dart\nWidget build(BuildContext context) {\n return CupertinoPageScaffold(\n child: ListView(\n children: [\n Tab2Header(),\n ...buildTab2Conversation(),\n ],\n ),\n );\n}\n```\n\n```dart\nvar ints = [1, 2, 3];\nprint(['a', ...ints.map((i) => i.toString()), 'c');\n```\n\n```dart\nvar things;\nvar l = ['a', ...?things];\n```", "sinceDartSdk": "2.3" @@ -2407,11 +2197,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** specifying a type annotation for uninitialized variables and fields.\n\nForgoing type annotations for uninitialized variables is a bad practice because\nyou may accidentally assign them to a type that you didn't originally intend to.\n\n**BAD:**\n```dart\nclass BadClass {\n static var bar; // LINT\n var foo; // LINT\n\n void method() {\n var bar; // LINT\n bar = 5;\n print(bar);\n }\n}\n```\n\n**BAD:**\n```dart\nvoid aFunction() {\n var bar; // LINT\n bar = 5;\n ...\n}\n```\n\n**GOOD:**\n```dart\nclass GoodClass {\n static var bar = 7;\n var foo = 42;\n int baz; // OK\n\n void method() {\n int baz;\n var bar = 5;\n ...\n }\n}\n```", "sinceDartSdk": "2.0" @@ -2437,11 +2223,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DO** specify a deprecation message (with migration instructions and/or a\nremoval schedule) in the `Deprecated` constructor.\n\n**BAD:**\n```dart\n@deprecated\nvoid oldFunction(arg1, arg2) {}\n```\n\n**GOOD:**\n```dart\n@Deprecated(\"\"\"\n[oldFunction] is being deprecated in favor of [newFunction] (with slightly\ndifferent parameters; see [newFunction] for more information). [oldFunction]\nwill be removed on or after the 4.0.0 release.\n\"\"\")\nvoid oldFunction(arg1, arg2) {}\n```", "sinceDartSdk": "2.2" @@ -2469,10 +2251,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** create recursive getters.\n\nRecursive getters are getters which return themselves as a value. This is\nusually a typo.\n\n**BAD:**\n```dart\nint get field => field; // LINT\n```\n\n**BAD:**\n```dart\nint get otherField {\n return otherField; // LINT\n}\n```\n\n**GOOD:**\n```dart\nint get field => _field;\n```", "sinceDartSdk": "2.0" @@ -2498,11 +2277,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DO** Use secure urls in `pubspec.yaml`.\n\nUse `https` instead of `http` or `git:`.\n\n**BAD:**\n```yaml\nrepository: http://github.com/dart-lang/example\n```\n\n```yaml\ngit:\n url: git://github.com/dart-lang/example/example.git\n```\n\n**GOOD:**\n```yaml\nrepository: https://github.com/dart-lang/example\n```", "sinceDartSdk": "2.16" @@ -2516,9 +2291,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Use `SizedBox` to add whitespace to a layout.\n\nA `Container` is a heavier Widget than a `SizedBox`, and as bonus, `SizedBox`\nhas a `const` constructor.\n\n**BAD:**\n```dart\nWidget buildRow() {\n return Row(\n children: [\n const MyLogo(),\n Container(width: 4),\n const Expanded(\n child: Text('...'),\n ),\n ],\n );\n}\n```\n\n**GOOD:**\n```dart\nWidget buildRow() {\n return Row(\n children: const [\n MyLogo(),\n SizedBox(width: 4),\n Expanded(\n child: Text('...'),\n ),\n ],\n );\n}\n```", "sinceDartSdk": "2.9" @@ -2546,10 +2319,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/documentation#do-use--doc-comments-to-document-members-and-types):\n\n**DO** use `///` for documentation comments.\n\nAlthough Dart supports two syntaxes of doc comments (`///` and `/**`), we\nprefer using `///` for doc comments.\n\n**GOOD:**\n```dart\n/// Parses a set of option strings. For each option:\n///\n/// * If it is `null`, then it is ignored.\n/// * If it is a string, then [validate] is called on it.\n/// * If it is any other type, it is *not* validated.\nvoid parse(List options) {\n // ...\n}\n```\n\nWithin a doc comment, you can use markdown for formatting.", "sinceDartSdk": "2.0" @@ -2563,9 +2333,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Sort child properties last in widget instance creations. This improves\nreadability and plays nicest with UI as Code visualization in IDEs with UI as\nCode Guides in editors (such as IntelliJ) where Properties in the correct order\nappear clearly associated with the constructor call and separated from the\nchildren.\n\n**BAD:**\n```dart\nreturn Scaffold(\n appBar: AppBar(\n title: Text(widget.title),\n ),\n body: Center(\n child: Column(\n children: [\n Text(\n 'You have pushed the button this many times:',\n ),\n Text(\n '$_counter',\n style: Theme.of(context).textTheme.display1,\n ),\n ],\n mainAxisAlignment: MainAxisAlignment.center,\n ),\n widthFactor: 0.5,\n ),\n floatingActionButton: FloatingActionButton(\n child: Icon(Icons.add),\n onPressed: _incrementCounter,\n tooltip: 'Increment',\n ),\n);\n```\n\n**GOOD:**\n```dart\nreturn Scaffold(\n appBar: AppBar(\n title: Text(widget.title),\n ),\n body: Center(\n widthFactor: 0.5,\n child: Column(\n mainAxisAlignment: MainAxisAlignment.center,\n children: [\n Text(\n 'You have pushed the button this many times:',\n ),\n Text(\n '$_counter',\n style: Theme.of(context).textTheme.display1,\n ),\n ],\n ),\n ),\n floatingActionButton: FloatingActionButton(\n onPressed: _incrementCounter,\n tooltip: 'Increment',\n child: Icon(Icons.add),\n ),\n);\n```\n\nException: It's allowed to have parameter with a function expression after the\n`child` property.", "sinceDartSdk": "2.4" @@ -2697,10 +2465,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/design#dont-type-annotate-initializing-formals):\n\n**DON'T** type annotate initializing formals.\n\nIf a constructor parameter is using `this.x` to initialize a field, then the\ntype of the parameter is understood to be the same type as the field. If a\na constructor parameter is using `super.x` to forward to a super constructor,\nthen the type of the parameter is understood to be the same as the super\nconstructor parameter.\n\nType annotating an initializing formal with a different type than that of the\nfield is OK.\n\n**BAD:**\n```dart\nclass Point {\n int x, y;\n Point(int this.x, int this.y);\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y);\n}\n```\n\n**BAD:**\n```dart\nclass A {\n int a;\n A(this.a);\n}\n\nclass B extends A {\n B(int super.a);\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n int a;\n A(this.a);\n}\n\nclass B extends A {\n B(super.a);\n}\n```", "sinceDartSdk": "2.0" @@ -2713,11 +2478,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "If you meant to test if the object has type `Foo`, instead write `Foo _`.\n\n**BAD:**\n```dart\nvoid f(Object? x) {\n if (x case num) {\n print('int or double');\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid f(Object? x) {\n if (x case num _) {\n print('int or double');\n }\n}\n```\n\nIf you do mean to test that the matched value (which you expect to have the\ntype `Type`) is equal to the type literal `Foo`, then this lint can be\nsilenced using `const (Foo)`.\n\n**BAD:**\n```dart\nvoid f(Object? x) {\n if (x case int) {\n print('int');\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid f(Object? x) {\n if (x case const (int)) {\n print('int');\n }\n}\n```", "sinceDartSdk": "3.0" @@ -2743,11 +2504,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "needsFix", "details": "**DON'T** use angle-bracketed text, `<…>`, in a doc comment unless you want to\nwrite an HTML tag or link.\n\nMarkdown allows HTML tags as part of the Markdown code, so you can write, for\nexample, `T1`. Markdown does not restrict the allowed tags, it just\nincludes the tags verbatim in the output.\n\nDartdoc only allows some known and valid HTML tags, and will omit any disallowed\nHTML tag from the output. See the list of allowed tags and directives below.\nYour doc comment should not contain any HTML tags that are not on this list.\n\nMarkdown also allows you to write an \"auto-link\" to an URL as for example\n``, delimited only by `<...>`. Such a link is\nallowed by Dartdoc as well.\nA `<...>` delimited text is an auto-link if it is a valid absolute URL, starting\nwith a scheme of at least two characters followed by a colon, like\n``.\n\nAny other other occurrence of `` or `` is likely a mistake\nand this lint will warn about it.\nIf something looks like an HTML tag, meaning it starts with `<` or ``, then it's considered an\ninvalid HTML tag unless it is an auto-link, or it starts with an *allowed*\nHTML tag.\n\nSuch a mistake can, for example, happen if writing Dart code with type arguments\noutside of a code span, for example `The type List is ...`, where ``\nlooks like an HTML tag. Missing the end quote of a code span can have the same\neffect: ``The type `List is ...`` will also treat `` as an HTML tag.\n\nAllows the following HTML directives: HTML comments, ``, processing\ninstructions, ``, CDATA-sections, and `<[CDATA...]>`.\nAllows DartDoc links like `[List]` which are not after a `]` or before a\n`[` or `(`, and allows the following recognized HTML tags:\n`a`, `abbr`, `address`, `area`, `article`, `aside`, `audio`, `b`,\n`bdi`, `bdo`, `blockquote`, `br`, `button`, `canvas`, `caption`,\n`cite`, `code`, `col`, `colgroup`, `data`, `datalist`, `dd`, `del`,\n`dfn`, `div`, `dl`, `dt`, `em`, `fieldset`, `figcaption`, `figure`,\n`footer`, `form`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `header`, `hr`,\n`i`, `iframe`, `img`, `input`, `ins`, `kbd`, `keygen`, `label`,\n`legend`, `li`, `link`, `main`, `map`, `mark`, `meta`, `meter`, `nav`,\n`noscript`, `object`, `ol`, `optgroup`, `option`, `output`, `p`,\n`param`, `pre`, `progress`, `q`, `s`, `samp`, `script`, `section`,\n`select`, `small`, `source`, `span`, `strong`, `style`, `sub`, `sup`,\n`table`, `tbody`, `td`, `template`, `textarea`, `tfoot`, `th`, `thead`,\n`time`, `title`, `tr`, `track`, `u`, `ul`, `var`, `video` and `wbr`.\n\n**BAD:**\n```dart\n/// The type List.\n/// -> = \n```\n\n**GOOD:**\n```dart\n/// The type `List`.\n/// The type [List]\n/// ` -> = `\n/// \\ -> \\ = \\`\n/// \n```", "sinceDartSdk": "3.5" @@ -2774,10 +2531,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** using braces in interpolation when not needed.\n\nIf you're just interpolating a simple identifier, and it's not immediately\nfollowed by more alphanumeric text, the `{}` can and should be omitted.\n\n**BAD:**\n```dart\nprint(\"Hi, ${name}!\");\n```\n\n**GOOD:**\n```dart\nprint(\"Hi, $name!\");\n```", "sinceDartSdk": "2.0" @@ -2805,10 +2559,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** repeating `const` keyword in a `const` context.\n\n**BAD:**\n```dart\nclass A { const A(); }\nm(){\n const a = const A();\n final b = const [const A()];\n}\n```\n\n**GOOD:**\n```dart\nclass A { const A(); }\nm(){\n const a = A();\n final b = const [A()];\n}\n```", "sinceDartSdk": "2.0" @@ -2822,10 +2573,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** using the default unnamed Constructor over `.new`.\n\nGiven a class `C`, the named unnamed constructor `C.new` refers to the same\nconstructor as the unnamed `C`. As such it adds nothing but visual noise to\ninvocations and should be avoided (unless being used to identify a constructor\ntear-off).\n\n**BAD:**\n```dart\nclass A {\n A.new(); // LINT\n}\n\nvar a = A.new(); // LINT\n```\n\n**GOOD:**\n```dart\nclass A {\n A.ok();\n}\n\nvar a = A();\nvar aa = A.ok();\nvar makeA = A.new;\n```", "sinceDartSdk": "2.15" @@ -2856,10 +2604,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#dont-wrap-a-field-in-a-getter-and-setter-unnecessarily):\n\n**AVOID** wrapping fields in getters and setters just to be \"safe\".\n\nIn Java and C#, it's common to hide all fields behind getters and setters (or\nproperties in C#), even if the implementation just forwards to the field. That\nway, if you ever need to do more work in those members, you can do it without needing\nto touch the callsites. This is because calling a getter method is different\nthan accessing a field in Java, and accessing a property isn't binary-compatible\nwith accessing a raw field in C#.\n\nDart doesn't have this limitation. Fields and getters/setters are completely\nindistinguishable. You can expose a field in a class and later wrap it in a\ngetter and setter without having to touch any code that uses that field.\n\n**BAD:**\n```dart\nclass Box {\n var _contents;\n get contents => _contents;\n set contents(value) {\n _contents = value;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n var contents;\n}\n```", "sinceDartSdk": "2.0" @@ -2885,10 +2630,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** not specify the `late` modifier for top-level and static variables\nwhen the declaration contains an initializer.\n\nTop-level and static variables with initializers are already evaluated lazily\nas if they are marked `late`.\n\n**BAD:**\n```dart\nlate String badTopLevel = '';\n```\n\n**GOOD:**\n```dart\nString goodTopLevel = '';\n```\n\n**BAD:**\n```dart\nclass BadExample {\n static late String badStatic = '';\n}\n```\n\n**GOOD:**\n```dart\nclass GoodExample {\n late String goodStatic;\n}\n```", "sinceDartSdk": "2.16" @@ -2916,10 +2658,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** have a library name in a `library` declaration.\n\nLibrary names are not necessary.\n\nA library does not need a library declaration, but one can be added to attach\nlibrary documentation and library metadata to. A declaration of `library;` is\nsufficient for those uses.\n\nThe only *use* of a library name is for a `part` file to refer back to its\nowning library, but part files should prefer to use a string URI to refer back\nto the library file, not a library name.\n\nIf a library name is added to a library declaration, it introduces the risk of\nname *conflicts*. It's a compile-time error if two libraries in the same program\nhave the same library name. To avoid that, library names tend to be long,\nincluding the package name and path, just to avoid accidental name clashes. That\nmakes such library names hard to read, and not even useful as documentation.\n\n**BAD:**\n```dart\n/// This library has a long name.\nlibrary magnificator.src.helper.bananas;\n```\n\n```dart\nlibrary utils; // Not as verbose, but risks conflicts.\n```\n\n**GOOD:**\n```dart\n/// This library is awesome.\nlibrary;\n\npart \"apart.dart\"; // contains: `part of \"good_library.dart\";`\n```", "sinceDartSdk": "3.4" @@ -2934,10 +2673,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** new keyword to create instances.\n\n**BAD:**\n```dart\nclass A { A(); }\nm(){\n final a = new A();\n}\n```\n\n**GOOD:**\n```dart\nclass A { A(); }\nm(){\n final a = A();\n}\n```", "sinceDartSdk": "2.0" @@ -2952,10 +2688,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** `null` in `null`-aware assignment.\n\nUsing `null` on the right-hand side of a `null`-aware assignment effectively\nmakes the assignment redundant.\n\n**BAD:**\n```dart\nvar x;\nx ??= null;\n```\n\n**GOOD:**\n```dart\nvar x;\nx ??= 1;\n```", "sinceDartSdk": "2.0" @@ -2995,10 +2728,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**AVOID** using `null` as an operand in `??` operators.\n\nUsing `null` in an `if null` operator is redundant, regardless of which side\n`null` is used on.\n\n**BAD:**\n```dart\nvar x = a ?? null;\nvar y = null ?? 1;\n```\n\n**GOOD:**\n```dart\nvar x = a ?? 1;\n```", "sinceDartSdk": "2.0" @@ -3011,10 +2741,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Use a non-nullable type for a final variable initialized with a non-nullable\nvalue.\n\n**BAD:**\n```dart\nfinal int? i = 1;\n```\n\n**GOOD:**\n```dart\nfinal int i = 1;\n```", "sinceDartSdk": "2.10" @@ -3027,11 +2754,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** override a method to do a super method invocation with same parameters.\n\n**BAD:**\n```dart\nclass A extends B {\n @override\n void foo() {\n super.foo();\n }\n}\n```\n\n**GOOD:**\n```dart\nclass A extends B {\n @override\n void foo() {\n doSomethingElse();\n }\n}\n```\n\nIt's valid to override a member in the following cases:\n\n* if a type (return type or a parameter type) is not the exactly the same as the\n super member,\n* if the `covariant` keyword is added to one of the parameters,\n* if documentation comments are present on the member,\n* if the member has annotations other than `@override`,\n* if the member is not annotated with `@protected`, and the super member is.\n\n`noSuchMethod` is a special method and is not checked by this rule.", "sinceDartSdk": "2.0" @@ -3087,10 +2810,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Remove unnecessary backslashes in strings.\n\n**BAD:**\n```dart\n'this string contains 2 \\\"double quotes\\\" ';\n\"this string contains 2 \\'single quotes\\' \";\n```\n\n**GOOD:**\n```dart\n'this string contains 2 \"double quotes\" ';\n\"this string contains 2 'single quotes' \";\n```", "sinceDartSdk": "2.8" @@ -3104,10 +2824,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use string interpolation if there's only a string expression in it.\n\n**BAD:**\n```dart\nString message;\nString o = '$message';\n```\n\n**GOOD:**\n```dart\nString message;\nString o = message;\n```", "sinceDartSdk": "2.8" @@ -3122,10 +2839,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-this-when-not-needed-to-avoid-shadowing):\n\n**DON'T** use `this` when not needed to avoid shadowing.\n\n**BAD:**\n```dart\nclass Box {\n int value;\n void update(int newValue) {\n this.value = newValue;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n int value;\n void update(int newValue) {\n value = newValue;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n int value;\n void update(int value) {\n this.value = value;\n }\n}\n```", "sinceDartSdk": "2.0" @@ -3138,10 +2852,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Unnecessary `toList()` in spreads.\n\n**BAD:**\n```dart\nchildren: [\n ...['foo', 'bar', 'baz'].map((String s) => Text(s)).toList(),\n]\n```\n\n**GOOD:**\n```dart\nchildren: [\n ...['foo', 'bar', 'baz'].map((String s) => Text(s)),\n]\n```", "sinceDartSdk": "2.18" @@ -3167,11 +2878,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "needsEvaluation", "details": "**DON'T** Compare references of unrelated types for equality.\n\nComparing references of a type where neither is a subtype of the other most\nlikely will return `false` and might not reflect programmer's intent.\n\n`Int64` and `Int32` from `package:fixnum` allow comparing to `int` provided\nthe `int` is on the right hand side. The lint allows this as a special case.\n\n**BAD:**\n```dart\nvoid someFunction() {\n var x = '1';\n if (x == 1) print('someFunction'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction1() {\n String x = '1';\n if (x == 1) print('someFunction1'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction13(DerivedClass2 instance) {\n var other = DerivedClass3();\n\n if (other == instance) print('someFunction13'); // LINT\n}\n\nclass ClassBase {}\n\nclass DerivedClass1 extends ClassBase {}\n\nabstract class Mixin {}\n\nclass DerivedClass2 extends ClassBase with Mixin {}\n\nclass DerivedClass3 extends ClassBase implements Mixin {}\n```\n\n**GOOD:**\n```dart\nvoid someFunction2() {\n var x = '1';\n var y = '2';\n if (x == y) print(someFunction2); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction3() {\n for (var i = 0; i < 10; i++) {\n if (i == 0) print(someFunction3); // OK\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction4() {\n var x = '1';\n if (x == null) print(someFunction4); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction7() {\n List someList;\n\n if (someList.length == 0) print('someFunction7'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction8(ClassBase instance) {\n DerivedClass1 other;\n\n if (other == instance) print('someFunction8'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction10(unknown) {\n var what = unknown - 1;\n for (var index = 0; index < unknown; index++) {\n if (what == index) print('someFunction10'); // OK\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction11(Mixin instance) {\n var other = DerivedClass2();\n\n if (other == instance) print('someFunction11'); // OK\n if (other != instance) print('!someFunction11'); // OK\n}\n\nclass ClassBase {}\n\nabstract class Mixin {}\n\nclass DerivedClass2 extends ClassBase with Mixin {}\n```", "sinceDartSdk": "2.0" @@ -3198,9 +2905,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** use `BuildContext` across asynchronous gaps.\n\nStoring `BuildContext` for later usage can easily lead to difficult to diagnose\ncrashes. Asynchronous gaps are implicitly storing `BuildContext` and are some of\nthe easiest to overlook when writing code.\n\nWhen a `BuildContext` is used, a `mounted` property must be checked after an\nasynchronous gap, depending on how the `BuildContext` is accessed:\n\n* When using a `State`'s `context` property, the `State`'s `mounted` property\n must be checked.\n* For other `BuildContext` instances (like a local variable or function\n argument), the `BuildContext`'s `mounted` property must be checked.\n\n**BAD:**\n```dart\nvoid onButtonTapped(BuildContext context) async {\n await Future.delayed(const Duration(seconds: 1));\n Navigator.of(context).pop();\n}\n```\n\n**GOOD:**\n```dart\nvoid onButtonTapped(BuildContext context) {\n Navigator.of(context).pop();\n}\n```\n\n**GOOD:**\n```dart\nvoid onButtonTapped(BuildContext context) async {\n await Future.delayed(const Duration(seconds: 1));\n\n if (!context.mounted) return;\n Navigator.of(context).pop();\n}\n```\n\n**GOOD:**\n```dart\nabstract class MyState extends State {\n void foo() async {\n await Future.delayed(const Duration(seconds: 1));\n if (!mounted) return; // Checks `this.mounted`, not `context.mounted`.\n Navigator.of(context).pop();\n }\n}\n```", "sinceDartSdk": "2.13" @@ -3255,9 +2960,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**PREFER** an 8-digit hexadecimal integer (for example, 0xFFFFFFFF) to\ninstantiate a Color. Colors have four 8-bit channels, which adds up to 32 bits,\nso Colors are described using a 32-bit integer.\n\n**BAD:**\n```dart\nColor(1);\nColor(0x000001);\n```\n\n**GOOD:**\n```dart\nColor(0x00000001);\n```", "sinceDartSdk": "2.2" @@ -3270,10 +2973,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "Use generic function type syntax for parameters.\n\n**BAD:**\n```dart\nIterable where(bool predicate(T element)) {}\n```\n\n**GOOD:**\n```dart\nIterable where(bool Function(T) predicate) {}\n```", "sinceDartSdk": "2.1" @@ -3314,9 +3014,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DO** use key in widget constructors.\n\nIt's a good practice to expose the ability to provide a key when creating public\nwidgets.\n\n**BAD:**\n```dart\nclass MyPublicWidget extends StatelessWidget {\n}\n```\n\n**GOOD:**\n```dart\nclass MyPublicWidget extends StatelessWidget {\n MyPublicWidget({super.key});\n}\n```", "sinceDartSdk": "2.8" @@ -3369,10 +3067,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-rethrow-to-rethrow-a-caught-exception):\n\n**DO** use rethrow to rethrow a caught exception.\n\nAs Dart provides rethrow as a feature, it should be used to improve terseness\nand readability.\n\n**BAD:**\n```dart\ntry {\n somethingRisky();\n} catch(e) {\n if (!canHandle(e)) throw e;\n handle(e);\n}\n```\n\n**GOOD:**\n```dart\ntry {\n somethingRisky();\n} catch(e) {\n if (!canHandle(e)) rethrow;\n handle(e);\n}\n```", "sinceDartSdk": "2.0" @@ -3412,11 +3107,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-strings-in-part-of-directives):\n\n**DO** use strings in `part of` directives.\n\n**BAD:**\n\n```dart\npart of my_library;\n```\n\n**GOOD:**\n\n```dart\npart of '../../my_library.dart';\n```", "sinceDartSdk": "2.19" @@ -3429,10 +3120,7 @@ ], "state": "experimental", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "\"Forwarding constructor\"s, that do nothing except forward parameters to their\nsuperclass constructors should take advantage of super-initializer parameters\nrather than repeating the names of parameters when passing them to the\nsuperclass constructors. This makes the code more concise and easier to read\nand maintain.\n\n**DO** use super-initializer parameters where possible.\n\n**BAD:**\n```dart\nclass A {\n A({int? x, int? y});\n}\nclass B extends A {\n B({int? x, int? y}) : super(x: x, y: y);\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n A({int? x, int? y});\n}\nclass B extends A {\n B({super.x, super.y});\n}\n```", "sinceDartSdk": "2.17" @@ -3485,11 +3173,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DO** use valid regular expression syntax when creating regular expression\ninstances.\n\nRegular expressions created with invalid syntax will throw a `FormatException`\nat runtime so should be avoided.\n\n**BAD:**\n```dart\nprint(RegExp(r'(').hasMatch('foo()'));\n```\n\n**GOOD:**\n```dart\nprint(RegExp(r'\\(').hasMatch('foo()'));\n```", "sinceDartSdk": "2.0" @@ -3502,11 +3186,7 @@ ], "state": "stable", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** assign to `void`.\n\n**BAD:**\n```dart\nclass A {\n T value;\n void test(T arg) { }\n}\n\nvoid main() {\n A a = A();\n a.value = 1; // LINT\n a.test(1); // LINT\n}\n```", "sinceDartSdk": "2.0" diff --git a/pkg/linter/tool/scorecard.dart b/pkg/linter/tool/scorecard.dart index 0668d26bc20..c2ed98c6cec 100644 --- a/pkg/linter/tool/scorecard.dart +++ b/pkg/linter/tool/scorecard.dart @@ -14,7 +14,7 @@ import 'package:linter/src/rules.dart'; import 'package:linter/src/utils.dart'; import '../tool/util/path_utils.dart'; -import 'crawl.dart'; +import 'lint_sets.dart'; import 'parse.dart'; void main() async { @@ -192,8 +192,8 @@ class ScoreCard { static Future calculate() async { var lintsWithFixes = _getLintsWithFixes(); var lintsWithAssists = _getLintsWithAssists(); - var flutterRuleset = await flutterRules; - var flutterRepoRuleset = await flutterRepoRules; + var flutterRuleset = await flutterUserLints; + var flutterRepoRuleset = await flutterRepoLints; var scorecard = ScoreCard(); for (var lint in registeredLints!) { diff --git a/pkg/linter/tool/util/score_utils.dart b/pkg/linter/tool/util/score_utils.dart deleted file mode 100644 index 24aae6c293e..00000000000 --- a/pkg/linter/tool/util/score_utils.dart +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:analyzer/src/lint/config.dart'; -import 'package:http/http.dart' as http; -import 'package:linter/src/utils.dart'; - -List? _coreRules; - -List? _flutterRules; - -List? _recommendedRules; - -Future> get coreRules async => - _coreRules ??= await _readCoreLints(); - -Future> get flutterRules async => - _flutterRules ??= await _readFlutterLints(); - -Future> get recommendedRules async => - _recommendedRules ??= await _readRecommendedLints(); - -Future> fetchRules(Uri optionsUrl) async { - var config = await _fetchConfig(optionsUrl); - if (config == null) { - printToConsole('no config found for: $optionsUrl (SKIPPED)'); - return []; - } - var rules = []; - for (var ruleConfig in config.ruleConfigs) { - var name = ruleConfig.name; - if (name != null) { - rules.add(name); - } - } - return rules; -} - -Future _fetchConfig(Uri url) async { - printToConsole('loading $url...'); - var req = await http.get(url); - return processAnalysisOptionsFile(req.body); -} - -// TODO(pq): update `scorecard.dart` to reuse these fetch functions. -Future> _fetchLints(String url) async { - try { - var req = await http.get(Uri.parse(url)); - return _readLints(req.body); - } on http.ClientException { - return []; - } -} - -Future> _readCoreLints() async => _fetchLints( - 'https://raw.githubusercontent.com/dart-lang/lints/main/lib/core.yaml'); - -// TODO(pq): de-duplicate these fetches / URIs -Future> _readFlutterLints() async => _fetchLints( - 'https://raw.githubusercontent.com/flutter/packages/main/packages/flutter_lints/lib/flutter.yaml'); - -List _readLints(String contents) { - var lintConfigs = processAnalysisOptionsFile(contents); - if (lintConfigs == null) { - return []; - } - return lintConfigs.ruleConfigs.map((c) => c.name ?? '').toList(); -} - -Future> _readRecommendedLints() async => _fetchLints( - 'https://raw.githubusercontent.com/dart-lang/lints/main/lib/recommended.yaml');