diff --git a/analyzers/dart-analyze/.deepsource/analyzer/analyzer.toml b/analyzers/dart-analyze/.deepsource/analyzer/analyzer.toml index bad980f6..34ec67c5 100644 --- a/analyzers/dart-analyze/.deepsource/analyzer/analyzer.toml +++ b/analyzers/dart-analyze/.deepsource/analyzer/analyzer.toml @@ -3,5 +3,5 @@ category = "lang" name = "Dart Analyze" shortcode = "dart-analyze" status = "active" -tool_latest_version = "3.2.0" +tool_latest_version = "3.1.5" description = "Dart analyze is a command that comes with the Dart SDK that performs static analysis that ensures your code adheres to best practices." diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1001.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1001.md index 7de10418..f377db85 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1001.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1001.md @@ -1,21 +1,41 @@ --- -title: "Use interpolation to compose strings and values." -verbose_name: "prefer_interpolation_to_compose_strings" -category: "antipattern" +title: "Avoid relative imports for files in `lib/`" +verbose_name: "always_use_package_imports" +category: "bug-risk" weight: 70 severity: "major" --- -**PREFER** using interpolation to compose strings and values. +**DO** avoid relative imports for files in `lib/`. -Using interpolation when composing strings and values is usually easier to write -and read than concatenation. +When mixing relative and absolute imports it's possible to create confusion +where the same member gets imported in two different ways. One way to avoid +that is to ensure you consistently use absolute imports for files within the +`lib/` directory. + +This is the opposite of 'prefer_relative_imports'. + +You can also use 'avoid_relative_lib_imports' to disallow relative imports of +files within `lib/` directory outside of it (for example `test/`). **BAD:** ```dart -'Hello, ' + person.name + ' from ' + person.city + '.'; +import 'baz.dart'; + +import 'src/bag.dart' + +import '../lib/baz.dart'; + +... ``` **GOOD:** ```dart -'Hello, ${person.name} from ${person.city}.' +import 'package:foo/bar.dart'; + +import 'package:foo/baz.dart'; + +import 'package:foo/src/baz.dart'; +... ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1002.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1002.md index 6289d2c7..bbca79dd 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1002.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1002.md @@ -1,57 +1,84 @@ --- -title: "Don't override fields." -verbose_name: "overridden_fields" -category: "antipattern" +title: "Avoid method calls or property accesses on a "dynamic" target" +verbose_name: "avoid_dynamic_calls" +category: "bug-risk" weight: 70 severity: "major" --- -**DON'T** override fields. +**DO** avoid method calls or accessing properties on an object that is either +explicitly or implicitly statically typed "dynamic". Dynamic calls are treated +slightly different in every runtime environment and compiler, but most +production modes (and even some development modes) have both compile size and +runtime performance penalties associated with dynamic calls. -Overriding fields is almost always done unintentionally. Regardless, it is a -bad practice to do so. +Additionally, targets typed "dynamic" disables most static analysis, meaning it +is easier to lead to a runtime "NoSuchMethodError" or "NullError" than properly +statically typed Dart code. + +There is an exception to methods and properties that exist on "Object?": +- a.hashCode +- a.runtimeType +- a.noSuchMethod(someInvocation) +- a.toString() + +... these members are dynamically dispatched in the web-based runtimes, but not +in the VM-based ones. Additionally, they are so common that it would be very +punishing to disallow `any.toString()` or `any == true`, for example. + +Note that despite "Function" being a type, the semantics are close to identical +to "dynamic", and calls to an object that is typed "Function" will also trigger +this lint. **BAD:** ```dart -class Base { - Object field = 'lorem'; +void explicitDynamicType(dynamic object) { + print(object.foo()); +} + +void implicitDynamicType(object) { + print(object.foo()); +} + +abstract class SomeWrapper { + T doSomething(); +} - Object something = 'change'; +void inferredDynamicType(SomeWrapper wrapper) { + var object = wrapper.doSomething(); + print(object.foo()); } -class Bad1 extends Base { - @override - final field = 'ipsum'; // LINT +void callDynamic(dynamic function) { + function(); } -class Bad2 extends Base { - @override - Object something = 'done'; // LINT +void functionType(Function function) { + function(); } ``` **GOOD:** ```dart -class Base { - Object field = 'lorem'; - - Object something = 'change'; +void explicitType(Fooable object) { + object.foo(); } -class Ok extends Base { - Object newField; // OK +void castedType(dynamic object) { + (object as Fooable).foo(); +} - final Object newFinal = 'ignore'; // OK +abstract class SomeWrapper { + T doSomething(); } -``` -**GOOD:** -```dart -abstract class BaseLoggingHandler { - Base transformer; +void inferredType(SomeWrapper wrapper) { + var object = wrapper.doSomething(); + object.foo(); } -class LogPrintHandler implements BaseLoggingHandler { - @override - Derived transformer; // OK +void functionTypeWithParameters(Function() function) { + function(); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1003.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1003.md index 9ec2e008..5e41d616 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1003.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1003.md @@ -1,49 +1,18 @@ --- -title: "Don't explicitly initialize variables to null." -verbose_name: "avoid_init_to_null" -category: "antipattern" +title: "Avoid empty else statements" +verbose_name: "avoid_empty_else" +category: "bug-risk" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/usage#dont-explicitly-initialize-variables-to-null): - -**DON'T** explicitly initialize variables to `null`. - -If a variable has a non-nullable type or is `final`, -Dart reports a compile error if you try to use it -before it has been definitely initialized. -If the variable is nullable and not `const` or `final`, -then it is implicitly initialized to `null` for you. -There's no concept of "uninitialized memory" in Dart -and no need to explicitly initialize a variable to `null` to be "safe". -Adding `= null` is redundant and unneeded. +**AVOID** empty else statements. **BAD:** ```dart -Item? bestDeal(List cart) { - Item? bestItem = null; - - for (final item in cart) { - if (bestItem == null || item.price < bestItem.price) { - bestItem = item; - } - } - - return bestItem; -} +if (x > y) + print("1"); +else ; + print("2"); ``` -**GOOD:** -```dart -Item? bestDeal(List cart) { - Item? bestItem; - - for (final item in cart) { - if (bestItem == null || item.price < bestItem.price) { - bestItem = item; - } - } - return bestItem; -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1004.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1004.md index f28fd2d6..a441fa83 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1004.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1004.md @@ -1,49 +1,50 @@ --- -title: "Prefer typing uninitialized variables and fields." -verbose_name: "prefer_typing_uninitialized_variables" -category: "antipattern" +title: "Avoid `print` calls in production code" +verbose_name: "avoid_print" +category: "bug-risk" weight: 70 severity: "major" --- -**PREFER** specifying a type annotation for uninitialized variables and fields. +**DO** avoid `print` calls in production code. -Forgoing type annotations for uninitialized variables is a bad practice because -you may accidentally assign them to a type that you didn't originally intend to. +For production code, consider using a logging framework. +If you are using Flutter, you can use `debugPrint` +or surround `print` calls with a check for `kDebugMode` **BAD:** ```dart -class BadClass { - static var bar; // LINT - var foo; // LINT - - void method() { - var bar; // LINT - bar = 5; - print(bar); - } +void f(int x) { + print('debug: $x'); + ... } ``` -**BAD:** + +**GOOD:** ```dart -void aFunction() { - var bar; // LINT - bar = 5; +void f(int x) { + debugPrint('debug: $x'); ... } ``` + **GOOD:** ```dart -class GoodClass { - static var bar = 7; - var foo = 42; - int baz; // OK - - void method() { - int baz; - var bar = 5; - ... +void f(int x) { + log('log: $x'); + ... +} +``` + + +**GOOD:** +```dart +void f(int x) { + if (kDebugMode) { + print('debug: $x'); } + ... } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1005.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1005.md index fe577e6f..82169664 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1005.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1005.md @@ -1,43 +1,36 @@ --- -title: "Always override `hashCode` if overriding `==`." -verbose_name: "hash_and_equals" +title: "Avoid relative imports for files in `lib/`" +verbose_name: "avoid_relative_lib_imports" category: "bug-risk" weight: 70 severity: "major" --- -**DO** override `hashCode` if overriding `==` and prefer overriding `==` if -overriding `hashCode`. +**DO** avoid relative imports for files in `lib/`. -Every object in Dart has a `hashCode`. Both the `==` operator and the -`hashCode` property of objects must be consistent in order for a common hash -map implementation to function properly. Thus, when overriding `==`, the -`hashCode` should also be overridden to maintain consistency. Similarly, if -`hashCode` is overridden, `==` should be also. +When mixing relative and absolute imports it's possible to create confusion +where the same member gets imported in two different ways. An easy way to avoid +that is to ensure you have no relative imports that include `lib/` in their +paths. + +You can also use 'always_use_package_imports' to disallow relative imports +between files within `lib/`. **BAD:** ```dart -class Bad { - final int value; - Bad(this.value); +import 'package:foo/bar.dart'; + +import '../lib/baz.dart'; - @override - bool operator ==(Object other) => other is Bad && other.value == value; -} +... ``` **GOOD:** ```dart -class Better { - final int value; - Better(this.value); - - @override - bool operator ==(Object other) => - other is Better && - other.runtimeType == runtimeType && - other.value == value; - - @override - int get hashCode => value.hashCode; -} +import 'package:foo/bar.dart'; + +import 'baz.dart'; + +... ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1006.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1006.md index adbc91ae..400b5cc4 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1006.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1006.md @@ -1,23 +1,43 @@ --- -title: "Prefer using mixins." -verbose_name: "prefer_mixin" -category: "antipattern" +title: "Avoid slow async `dart:io` methods" +verbose_name: "avoid_slow_async_io" +category: "bug-risk" weight: 70 severity: "major" --- -Dart 2.1 introduced a new syntax for mixins that provides a safe way for a mixin -to invoke inherited members using `super`. The new style of mixins should always -be used for types that are to be mixed in. As a result, this lint will flag any -uses of a class in a `with` clause. +**AVOID** using the following asynchronous file I/O methods because they are +much slower than their synchronous counterparts. + +* `Directory.exists` +* `Directory.stat` +* `File.lastModified` +* `File.exists` +* `File.stat` +* `FileSystemEntity.isDirectory` +* `FileSystemEntity.isFile` +* `FileSystemEntity.isLink` +* `FileSystemEntity.type` **BAD:** ```dart -class A {} -class B extends Object with A {} +import 'dart:io'; + +Future someFunction() async { + var file = File('/path/to/my/file'); + var now = DateTime.now(); + if ((await file.lastModified()).isBefore(now)) print('before'); // LINT +} ``` -**OK:** +**GOOD:** ```dart -mixin M {} -class C with M {} +import 'dart:io'; + +Future someFunction() async { + var file = File('/path/to/my/file'); + var now = DateTime.now(); + if (file.lastModifiedSync().isBefore(now)) print('before'); // OK +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1007.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1007.md index ed6d5d9c..9f0346a1 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1007.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1007.md @@ -1,27 +1,43 @@ --- -title: "Avoid lines longer than 80 characters." -verbose_name: "lines_longer_than_80_chars" -category: "antipattern" +title: "Avoid .toString() in production code since results may be minified" +verbose_name: "avoid_type_to_string" +category: "bug-risk" weight: 70 severity: "major" --- -**AVOID** lines longer than 80 characters +**DO** avoid calls to .toString() in production code, since it does not +contractually return the user-defined name of the Type (or underlying class). +Development-mode compilers where code size is not a concern use the full name, +but release-mode compilers often choose to minify these symbols. -Readability studies show that long lines of text are harder to read because your -eye has to travel farther when moving to the beginning of the next line. This is -why newspapers and magazines use multiple columns of text. +**BAD:** +```dart +void bar(Object other) { + if (other.runtimeType.toString() == 'Bar') { + doThing(); + } +} -If you really find yourself wanting lines longer than 80 characters, our -experience is that your code is likely too verbose and could be a little more -compact. The main offender is usually `VeryLongCamelCaseClassNames`. Ask -yourself, “Does each word in that type name tell me something critical or -prevent a name collision?” If not, consider omitting it. +Object baz(Thing myThing) { + return getThingFromDatabase(key: myThing.runtimeType.toString()); +} +``` + +**GOOD:** +```dart +void bar(Object other) { + if (other is Bar) { + doThing(); + } +} + +class Thing { + String get thingTypeKey => ... +} + +Object baz(Thing myThing) { + return getThingFromDatabase(key: myThing.thingTypeKey); +} +``` -Note that `dart format` does 99% of this for you, but the last 1% is you. It -does not split long string literals to fit in 80 columns, so you have to do -that manually. -We make an exception for URIs and file paths. When those occur in comments or -strings (usually in imports and exports), they may remain on a single line even -if they go over the line limit. This makes it easier to search source files for -a given path. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1008.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1008.md index 3b3aed23..62361ff5 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1008.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1008.md @@ -1,72 +1,20 @@ --- -title: "Don't reassign references to parameters of functions or methods." -verbose_name: "parameter_assignments" -category: "antipattern" +title: "Avoid types as parameter names" +verbose_name: "avoid_types_as_parameter_names" +category: "bug-risk" weight: 70 severity: "major" --- -**DON'T** assign new values to parameters of methods or functions. - -Assigning new values to parameters is generally a bad practice unless an -operator such as `??=` is used. Otherwise, arbitrarily reassigning parameters -is usually a mistake. - -**BAD:** -```dart -void badFunction(int parameter) { // LINT - parameter = 4; -} -``` - -**BAD:** -```dart -void badFunction(int required, {int optional: 42}) { // LINT - optional ??= 8; -} -``` +**AVOID** using a parameter name that is the same as an existing type. **BAD:** ```dart -void badFunctionPositional(int required, [int optional = 42]) { // LINT - optional ??= 8; -} -``` - -**BAD:** -```dart -class A { - void badMethod(int parameter) { // LINT - parameter = 4; - } -} +m(f(int)); ``` **GOOD:** ```dart -void ok(String parameter) { - print(parameter); -} +m(f(int v)); ``` -**GOOD:** -```dart -void actuallyGood(int required, {int optional}) { // OK - optional ??= ...; -} -``` -**GOOD:** -```dart -void actuallyGoodPositional(int required, [int optional]) { // OK - optional ??= ...; -} -``` - -**GOOD:** -```dart -class A { - void ok(String parameter) { - print(parameter); - } -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1009.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1009.md index dad83e2a..83ef5c0f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1009.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1009.md @@ -1,28 +1,19 @@ --- -title: "Put required named parameters first." -verbose_name: "always_put_required_named_parameters_first" -category: "antipattern" +title: "Avoid using web-only libraries outside Flutter web plugin packages" +verbose_name: "avoid_web_libraries_in_flutter" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** specify `required` on named parameter before other named parameters. +**AVOID** using web libraries, `dart:html`, `dart:js` and +`dart:js_util` in Flutter packages that are not web plugins. These libraries are +not supported outside a web context; functionality that depends on them will +fail at runtime in Flutter mobile, and their use is generally discouraged in +Flutter web. -**BAD:** -```dart -m({b, c, required a}) ; -``` +Web library access *is* allowed in: -**GOOD:** -```dart -m({required a, b, c}) ; -``` +* plugin packages that declare `web` as a supported context -**BAD:** -```dart -m({b, c, @required a}) ; -``` +otherwise, imports of `dart:html`, `dart:js` and `dart:js_util` are disallowed. -**GOOD:** -```dart -m({@required a, b, c}) ; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1010.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1010.md index bc0cc48f..23bf6ce5 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1010.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1010.md @@ -1,36 +1,58 @@ --- -title: "Only use double quotes for strings containing single quotes." -verbose_name: "prefer_single_quotes" -category: "antipattern" +title: "Cancel instances of dart.async.StreamSubscription" +verbose_name: "cancel_subscriptions" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** use single quotes where they wouldn't require additional escapes. +**DO** invoke `cancel` on instances of `dart.async.StreamSubscription`. -That means strings with an apostrophe may use double quotes so that the -apostrophe isn't escaped (note: we don't lint the other way around, ie, a single -quoted string with an escaped apostrophe is not flagged). +Cancelling instances of StreamSubscription prevents memory leaks and unexpected +behavior. -It's also rare, but possible, to have strings within string interpolations. In -this case, its much more readable to use a double quote somewhere. So double -quotes are allowed either within, or containing, an interpolated string literal. -Arguably strings within string interpolations should be its own type of lint. +**BAD:** +```dart +class A { + StreamSubscription _subscriptionA; // LINT + void init(Stream stream) { + _subscriptionA = stream.listen((_) {}); + } +} +``` **BAD:** ```dart -useStrings( - "should be single quote", - r"should be single quote", - r"""should be single quotes""") +void someFunction() { + StreamSubscription _subscriptionF; // LINT +} +``` + +**GOOD:** +```dart +class B { + StreamSubscription _subscriptionB; // OK + void init(Stream stream) { + _subscriptionB = stream.listen((_) {}); + } + + void dispose(filename) { + _subscriptionB.cancel(); + } +} ``` **GOOD:** ```dart -useStrings( - 'should be single quote', - r'should be single quote', - r\'''should be single quotes\''', - "here's ok", - "nested \${a ? 'strings' : 'can'} be wrapped by a double quote", - 'and nested \${a ? "strings" : "can be double quoted themselves"}'); +void someFunctionOK() { + StreamSubscription _subscriptionB; // OK + _subscriptionB.cancel(); +} ``` + +**Known limitations** + +This rule does not track all patterns of StreamSubscription instantiations and +cancellations. See [linter#317](https://github.com/dart-lang/linter/issues/317) +for more information. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1011.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1011.md index 260a888e..c26b96d8 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1011.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1011.md @@ -1,20 +1,57 @@ --- -title: "Avoid return types on setters." -verbose_name: "avoid_return_types_on_setters" -category: "antipattern" +title: "Close instances of `dart.core.Sink`" +verbose_name: "close_sinks" +category: "bug-risk" weight: 70 severity: "major" --- -**AVOID** return types on setters. +**DO** invoke `close` on instances of `dart.core.Sink`. -As setters do not return a value, declaring the return type of one is redundant. +Closing instances of Sink prevents memory leaks and unexpected behavior. **BAD:** ```dart -void set speed(int ms); +class A { + IOSink _sinkA; + void init(filename) { + _sinkA = File(filename).openWrite(); // LINT + } +} +``` + +**BAD:** +```dart +void someFunction() { + IOSink _sinkF; // LINT +} ``` **GOOD:** ```dart -set speed(int ms); +class B { + IOSink _sinkB; + void init(filename) { + _sinkB = File(filename).openWrite(); // OK + } + + void dispose(filename) { + _sinkB.close(); + } +} ``` + +**GOOD:** +```dart +void someFunctionOK() { + IOSink _sinkFOK; // OK + _sinkFOK.close(); +} +``` + +**Known limitations** + +This rule does not track all patterns of Sink instantiations and +closures. See [linter#1381](https://github.com/dart-lang/linter/issues/1381) +for more information. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1012.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1012.md index 29d5aead..40c5db82 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1012.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1012.md @@ -1,20 +1,59 @@ --- -title: "Sort combinator names alphabetically." -verbose_name: "combinators_ordering" -category: "antipattern" +title: "Invocation of various collection methods with arguments of unrelated types" +verbose_name: "collection_methods_unrelated_type" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** sort combinator names alphabetically. +**DON'T** invoke certain collection method with an argument with an unrelated +type. + +Doing this will invoke `==` on the collection's elements and most likely will +return `false`. + +An argument passed to a collection method should relate to the collection type +as follows: + +* an argument to `Iterable.contains` should be related to `E` +* an argument to `List.remove` should be related to `E` +* an argument to `Map.containsKey` should be related to `K` +* an argument to `Map.containsValue` should be related to `V` +* an argument to `Map.remove` should be related to `K` +* an argument to `Map.[]` should be related to `K` +* an argument to `Queue.remove` should be related to `E` +* an argument to `Set.lookup` should be related to `E` +* an argument to `Set.remove` should be related to `E` + +**BAD:** +```dart +void someFunction() { + var list = []; + if (list.contains('1')) print('someFunction'); // LINT +} +``` **BAD:** ```dart -import 'a.dart' show B, A hide D, C; -export 'a.dart' show B, A hide D, C; +void someFunction() { + var set = {}; + set.remove('1'); // LINT +} ``` **GOOD:** ```dart -import 'a.dart' show A, B hide C, D; -export 'a.dart' show A, B hide C, D; +void someFunction() { + var list = []; + if (list.contains(1)) print('someFunction'); // OK +} ``` + +**GOOD:** +```dart +void someFunction() { + var set = {}; + set.remove(1); // OK +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1013.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1013.md index 5f6d4ce1..1835fa7d 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1013.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1013.md @@ -1,43 +1,56 @@ --- -title: "Cascade consecutive method invocations on the same reference." -verbose_name: "cascade_invocations" -category: "antipattern" +title: "Only reference in scope identifiers in doc comments" +verbose_name: "comment_references" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** Use the cascading style when successively invoking methods on the same -reference. +**DO** reference only in scope identifiers in doc comments. -**BAD:** -```dart -SomeClass someReference = SomeClass(); -someReference.firstMethod(); -someReference.secondMethod(); -``` +If you surround things like variable, method, or type names in square brackets, +then [`dart doc`](https://dart.dev/tools/dart-doc) will look up the name and +link to its docs. For this all to work, ensure that all identifiers in docs +wrapped in brackets are in scope. + +For example, assuming `outOfScopeId` is out of scope: **BAD:** ```dart -SomeClass someReference = SomeClass(); -... -someReference.firstMethod(); -someReference.aProperty = value; -someReference.secondMethod(); +/// Return true if [value] is larger than [outOfScopeId]. +bool isOutOfRange(int value) { ... } ``` **GOOD:** ```dart -SomeClass someReference = SomeClass() - ..firstMethod() - ..aProperty = value - ..secondMethod(); +/// Return the larger of [a] or [b]. +int max_int(int a, int b) { ... } ``` -**GOOD:** -```dart -SomeClass someReference = SomeClass(); -... -someReference - ..firstMethod() - ..aProperty = value - ..secondMethod(); -``` +Note that the square bracket comment format is designed to allow comments to +refer to declarations using a fairly natural format but does not allow +*arbitrary expressions*. In particular, code references within square brackets +can consist of either + +- a single identifier where the identifier is any identifier in scope for the + comment (see the spec for what is in scope in doc comments), +- two identifiers separated by a period where the first identifier is the name + of a class that is in scope and the second is the name of a member declared in + the class, +- a single identifier followed by a pair of parentheses where the identifier is + the name of a class that is in scope (used to refer to the unnamed constructor + for the class), or +- two identifiers separated by a period and followed by a pair of parentheses + where the first identifier is the name of a class that is in scope and the + second is the name of a named constructor (not strictly necessary, but allowed + for consistency). + +**Known limitations** + +The `comment_references` linter rule aligns with the Dart analyzer's notion of +comment references, which is separate from Dartdoc's notion of comment +references. The linter rule may report comment references which cannot be +resolved by the analyzer, but which Dartdoc can. See +[dartdoc#1142](https://github.com/dart-lang/linter/issues/1142) for more +information. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1014.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1014.md index ec4659c0..1e7f8d00 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1014.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1014.md @@ -1,44 +1,79 @@ --- -title: "Use => for short members whose body is a single return statement." -verbose_name: "prefer_expression_function_bodies" -category: "antipattern" +title: "Avoid control flow in finally blocks" +verbose_name: "control_flow_in_finally" +category: "bug-risk" weight: 70 severity: "major" --- -**CONSIDER** using => for short members whose body is a single return statement. +**AVOID** control flow leaving finally blocks. + +Using control flow in finally blocks will inevitably cause unexpected behavior +that is hard to debug. **BAD:** ```dart -get width { - return right - left; +class BadReturn { + double nonCompliantMethod() { + try { + return 1 / 0; + } catch (e) { + print(e); + } finally { + return 1.0; // LINT + } + } } ``` **BAD:** ```dart -bool ready(num time) { - return minTime == null || minTime <= time; +class BadContinue { + double nonCompliantMethod() { + for (var o in [1, 2]) { + try { + print(o / 0); + } catch (e) { + print(e); + } finally { + continue; // LINT + } + } + return 1.0; + } } ``` **BAD:** ```dart -containsValue(String value) { - return getValues().contains(value); +class BadBreak { + double nonCompliantMethod() { + for (var o in [1, 2]) { + try { + print(o / 0); + } catch (e) { + print(e); + } finally { + break; // LINT + } + } + return 1.0; + } } ``` **GOOD:** ```dart -get width => right - left; +class Ok { + double compliantMethod() { + var i = 5; + try { + i = 1 / 0; + } catch (e) { + print(e); // OK + } + return i; + } +} ``` -**GOOD:** -```dart -bool ready(num time) => minTime == null || minTime <= time; -``` -**GOOD:** -```dart -containsValue(String value) => getValues().contains(value); -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1015.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1015.md index 9c8fd612..bad1a083 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1015.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1015.md @@ -1,47 +1,64 @@ --- -title: "Use collection literals when possible." -verbose_name: "prefer_collection_literals" -category: "antipattern" +title: "Avoid using deprecated elements from within the package in which they are declared" +verbose_name: "deprecated_member_use_from_same_package" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** use collection literals when possible. +Elements that are annotated with `@Deprecated` should not be referenced from +within the package in which they are declared. + +**AVOID** using deprecated elements. + +... **BAD:** ```dart -var addresses = Map(); -var uniqueNames = Set(); -var ids = LinkedHashSet(); -var coordinates = LinkedHashMap(); +// Declared in one library: +class Foo { + @Deprecated("Use 'm2' instead") + void m1() {} + + void m2({ + @Deprecated('This is an old parameter') int? p, + }) +} + +@Deprecated('Do not use') +int x = 0; + +// In the same or another library, but within the same package: +void m(Foo foo) { + foo.m1(); + foo.m2(p: 7); + x = 1; +} ``` +Deprecated elements can be used from within _other_ deprecated elements, in +order to allow for the deprecation of a collection of APIs together as one unit. + **GOOD:** ```dart -var addresses = {}; -var uniqueNames = {}; -var ids = {}; -var coordinates = {}; -``` +// Declared in one library: +class Foo { + @Deprecated("Use 'm2' instead") + void m1() {} -**EXCEPTIONS:** + void m2({ + @Deprecated('This is an old parameter') int? p, + }) +} -When a `LinkedHashSet` or `LinkedHashMap` is expected, a collection literal is -not preferred (or allowed). +@Deprecated('Do not use') +int x = 0; -```dart -void main() { - LinkedHashSet linkedHashSet = LinkedHashSet.from([1, 2, 3]); // OK - LinkedHashMap linkedHashMap = LinkedHashMap(); // OK - - printSet(LinkedHashSet()); // LINT - printHashSet(LinkedHashSet()); // OK - - printMap(LinkedHashMap()); // LINT - printHashMap(LinkedHashMap()); // OK +// In the same or another library, but within the same package: +@Deprecated('Do not use') +void m(Foo foo) { + foo.m1(); + foo.m2(p: 7); + x = 1; } - -void printSet(Set ids) => print('$ids!'); -void printHashSet(LinkedHashSet ids) => printSet(ids); -void printMap(Map map) => print('$map!'); -void printHashMap(LinkedHashMap map) => printMap(map); ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1016.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1016.md index 26928922..89806d5b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1016.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1016.md @@ -1,28 +1,56 @@ --- -title: "Avoid library directives unless they have documentation comments or annotations." -verbose_name: "unnecessary_library_directive" -category: "antipattern" +title: "DO reference all public properties in debug methods" +verbose_name: "diagnostic_describe_all_properties" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** use library directives if you want to document a library and/or annotate -a library. +**DO** reference all public properties in `debug` method implementations. + +Implementers of `Diagnosticable` should reference all public properties in +a `debugFillProperties(...)` or `debugDescribeChildren(...)` method +implementation to improve debuggability at runtime. + +Public properties are defined as fields and getters that are + +* not package-private (e.g., prefixed with `_`) +* not `static` or overriding +* not themselves `Widget`s or collections of `Widget`s + +In addition, the "debug" prefix is treated specially for properties in Flutter. +For the purposes of diagnostics, a property `foo` and a prefixed property +`debugFoo` are treated as effectively describing the same property and it is +sufficient to refer to one or the other. **BAD:** ```dart -library; +class Absorber extends Widget { + bool get absorbing => _absorbing; + bool _absorbing; + bool get ignoringSemantics => _ignoringSemantics; + bool _ignoringSemantics; + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('absorbing', absorbing)); + // Missing reference to ignoringSemantics + } +} ``` **GOOD:** ```dart -/// This library does important things -library; -``` - -```dart -@TestOn('js') -library; +class Absorber extends Widget { + bool get absorbing => _absorbing; + bool _absorbing; + bool get ignoringSemantics => _ignoringSemantics; + bool _ignoringSemantics; + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('absorbing', absorbing)); + properties.add(DiagnosticsProperty('ignoringSemantics', ignoringSemantics)); + } +} ``` -NOTE: Due to limitations with this lint, libraries with parts will not be -flagged for unnecessary library directives. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1017.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1017.md index b8f34bcc..3f0a96df 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1017.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1017.md @@ -1,24 +1,37 @@ --- -title: "$_descPrefix." -verbose_name: "unsafe_html" +title: "Don't invoke asynchronous functions in non-async blocks" +verbose_name: "discarded_futures" category: "bug-risk" weight: 70 severity: "major" --- -**AVOID** - -* assigning directly to the `href` field of an AnchorElement -* assigning directly to the `src` field of an EmbedElement, IFrameElement, or - ScriptElement -* assigning directly to the `srcdoc` field of an IFrameElement -* calling the `createFragment` method of Element -* calling the `open` method of Window -* calling the `setInnerHtml` method of Element -* calling the `Element.html` constructor -* calling the `DocumentFragment.html` constructor +Making asynchronous calls in non-`async` functions is usually the sign of a +programming error. In general these functions should be marked `async` and such +futures should likely be awaited (as enforced by `unawaited_futures`). +**DON'T** invoke asynchronous functions in non-`async` blocks. **BAD:** ```dart -var script = ScriptElement()..src = 'foo.js'; +void recreateDir(String path) { + deleteDir(path); + createDir(path); +} + +Future deleteDir(String path) async {} + +Future createDir(String path) async {} ``` + +**GOOD:** +```dart +Future recreateDir(String path) async { + await deleteDir(path); + await createDir(path); +} + +Future deleteDir(String path) async {} + +Future createDir(String path) async {} +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1018.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1018.md index 2f55e775..45c5cd50 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1018.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1018.md @@ -1,41 +1,36 @@ --- -title: "Avoid `throw` in finally block." -verbose_name: "throw_in_finally" +title: "Avoid empty statements" +verbose_name: "empty_statements" category: "bug-risk" weight: 70 severity: "major" --- -**AVOID** throwing exceptions in finally blocks. +**AVOID** empty statements. -Throwing exceptions in finally blocks will inevitably cause unexpected behavior -that is hard to debug. +Empty statements almost always indicate a bug. + +For example, **BAD:** ```dart -class BadThrow { - double nonCompliantMethod() { - try { - print('hello world! ${1 / 0}'); - } catch (e) { - print(e); - } finally { - throw 'Find the hidden error :P'; // LINT - } - } -} +if (complicated.expression.foo()); + bar(); ``` +Formatted with `dart format` the bug becomes obvious: + +```dart +if (complicated.expression.foo()) ; +bar(); + +``` + +Better to avoid the empty statement altogether. + **GOOD:** ```dart -class Ok { - double compliantMethod() { - var i = 5; - try { - i = 1 / 0; - } catch (e) { - print(e); // OK - } - return i; - } -} +if (complicated.expression.foo()) + bar(); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1019.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1019.md index e03b4cb2..23b6a12a 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1019.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1019.md @@ -1,33 +1,44 @@ --- -title: "Use string buffers to compose strings." -verbose_name: "use_string_buffers" -category: "antipattern" +title: "Always override `hashCode` if overriding `==`" +verbose_name: "hash_and_equals" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** use string buffers to compose strings. +**DO** override `hashCode` if overriding `==` and prefer overriding `==` if +overriding `hashCode`. -In most cases, using a string buffer is preferred for composing strings due to -its improved performance. +Every object in Dart has a `hashCode`. Both the `==` operator and the +`hashCode` property of objects must be consistent in order for a common hash +map implementation to function properly. Thus, when overriding `==`, the +`hashCode` should also be overridden to maintain consistency. Similarly, if +`hashCode` is overridden, `==` should be also. **BAD:** ```dart -String foo() { - final buffer = ''; - for (int i = 0; i < 10; i++) { - buffer += 'a'; // LINT - } - return buffer; +class Bad { + final int value; + Bad(this.value); + + @override + bool operator ==(Object other) => other is Bad && other.value == value; } ``` **GOOD:** ```dart -String foo() { - final buffer = StringBuffer(); - for (int i = 0; i < 10; i++) { - buffer.write('a'); - } - return buffer.toString(); +class Better { + final int value; + Better(this.value); + + @override + bool operator ==(Object other) => + other is Better && + other.runtimeType == runtimeType && + other.value == value; + + @override + int get hashCode => value.hashCode; } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1020.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1020.md index b1ed6d0c..65a36fc2 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1020.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1020.md @@ -1,34 +1,86 @@ --- -title: "Avoid double and int checks." -verbose_name: "avoid_double_and_int_checks" -category: "antipattern" +title: "Boolean expression composed only with literals" +verbose_name: "literal_only_boolean_expressions" +category: "bug-risk" weight: 70 severity: "major" --- -**AVOID** to check if type is double or int. +**DON'T** test for conditions composed only by literals, since the value can be +inferred at compile time. -When compiled to JS, integer values are represented as floats. That can lead to -some unexpected behavior when using either `is` or `is!` where the type is -either `int` or `double`. +Conditional statements using a condition which cannot be anything but FALSE have +the effect of making blocks of code non-functional. If the condition cannot +evaluate to anything but `true`, the conditional statement is completely +redundant, and makes the code less readable. +It is quite likely that the code does not match the programmer's intent. +Either the condition should be removed or it should be updated so that it does +not always evaluate to `true` or `false`. **BAD:** ```dart -f(num x) { - if (x is double) { - ... - } else if (x is int) { - ... - } +void bad() { + if (true) {} // LINT +} +``` + +**BAD:** +```dart +void bad() { + if (true && 1 != 0) {} // LINT +} +``` + +**BAD:** +```dart +void bad() { + if (1 != 0 && true) {} // LINT +} +``` + +**BAD:** +```dart +void bad() { + if (1 < 0 && true) {} // LINT +} +``` + +**BAD:** +```dart +void bad() { + if (true && false) {} // LINT +} +``` + +**BAD:** +```dart +void bad() { + if (1 != 0) {} // LINT } ``` +**BAD:** +```dart +void bad() { + if (true && 1 != 0 || 3 < 4) {} // LINT +} +``` + +**BAD:** +```dart +void bad() { + if (1 != 0 || 3 < 4 && true) {} // LINT +} +``` + +**NOTE:** that an exception is made for the common `while (true) { }` idiom, +which is often reasonably preferred to the equivalent `for (;;)`. + **GOOD:** ```dart -f(dynamic x) { - if (x is num) { - ... - } else { - ... +void good() { + while (true) { + // Do stuff. } } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1021.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1021.md index 1762b945..90bde0e0 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1021.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1021.md @@ -1,21 +1,30 @@ --- -title: "Put a single newline at end of file." -verbose_name: "eol_at_end_of_file" -category: "antipattern" +title: "Don't use adjacent strings in list" +verbose_name: "no_adjacent_strings_in_list" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** put a single newline at the end of non-empty files. +**DON'T** use adjacent strings in a list. + +This can indicate a forgotten comma. **BAD:** ```dart -a { -} +List list = [ + 'a' + 'b', + 'c', +]; ``` **GOOD:** ```dart -b { -} - <-- newline +List list = [ + 'a' + + 'b', + 'c', +]; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1022.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1022.md index edbb5035..ebef407e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1022.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1022.md @@ -1,29 +1,35 @@ --- -title: "Specify `@required` on named parameters without defaults." -verbose_name: "always_require_non_null_named_parameters" -category: "antipattern" +title: "Don't use more than one case with same value" +verbose_name: "no_duplicate_case_values" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** specify `@required` on named parameters without a default value on which -an `assert(param != null)` is done. +**DON'T** use more than one case with same value. + +This is usually a typo or changed value of constant. **BAD:** ```dart -m1({a}) { - assert(a != null); +const int A = 1; +switch (v) { + case 1: + case 2: + case A: + case 2: } ``` **GOOD:** ```dart -m1({@required a}) { - assert(a != null); -} - -m2({a: 1}) { - assert(a != null); +const int A = 1; +switch (v) { + case A: + case 2: } ``` -NOTE: Only asserts at the start of the bodies will be taken into account. +NOTE: this lint only reports duplicate cases in libraries opted in to Dart 2.19 +and below. In Dart 3.0 and after, duplicate cases are reported as dead code +by the analyzer. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1023.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1023.md index 520ae4f0..25181a9d 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1023.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1023.md @@ -1,50 +1,53 @@ --- -title: "Cancel instances of dart.async.StreamSubscription." -verbose_name: "cancel_subscriptions" +title: "Don't put any logic in createState" +verbose_name: "no_logic_in_create_state" category: "bug-risk" weight: 70 severity: "major" --- -**DO** invoke `cancel` on instances of `dart.async.StreamSubscription`. +**DON'T** put any logic in `createState()`. -Cancelling instances of StreamSubscription prevents memory leaks and unexpected -behavior. +Implementations of `createState()` should return a new instance +of a State object and do nothing more. Since state access is preferred +via the `widget` field, passing data to `State` objects using custom +constructor parameters should also be avoided and so further, the State +constructor is required to be passed no arguments. **BAD:** ```dart -class A { - StreamSubscription _subscriptionA; // LINT - void init(Stream stream) { - _subscriptionA = stream.listen((_) {}); - } +MyState global; + +class MyStateful extends StatefulWidget { + @override + MyState createState() { + global = MyState(); + return global; + } } ``` -**BAD:** ```dart -void someFunction() { - StreamSubscription _subscriptionF; // LINT +class MyStateful extends StatefulWidget { + @override + MyState createState() => MyState()..field = 42; } ``` -**GOOD:** ```dart -class B { - StreamSubscription _subscriptionB; // OK - void init(Stream stream) { - _subscriptionB = stream.listen((_) {}); - } - - void dispose(filename) { - _subscriptionB.cancel(); - } +class MyStateful extends StatefulWidget { + @override + MyState createState() => MyState(42); } ``` + **GOOD:** ```dart -void someFunctionOK() { - StreamSubscription _subscriptionB; // OK - _subscriptionB.cancel(); +class MyStateful extends StatefulWidget { + @override + MyState createState() { + return MyState(); + } } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1024.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1024.md index 69652223..eb48b5a3 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1024.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1024.md @@ -1,28 +1,107 @@ --- -title: "Only throw instances of classes extending either Exception or Error." -verbose_name: "only_throw_errors" -category: "antipattern" +title: "Don't assign a variable to itself" +verbose_name: "no_self_assignments" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** throw only instances of classes that extend `dart.core.Error` or -`dart.core.Exception`. +**DON'T** assign a variable to itself. Usually this is a mistake. -Throwing instances that do not extend `Error` or `Exception` is a bad practice; -doing this is usually a hack for something that should be implemented more -thoroughly. +**BAD:** +```dart +class C { + int x; + + C(int x) { + x = x; + } +} +``` + +**GOOD:** +```dart +class C { + int x; + + C(int x) : x = x; +} +``` + +**GOOD:** +```dart +class C { + int x; + + C(int x) { + this.x = x; + } +} +``` **BAD:** ```dart -void throwString() { - throw 'hello world!'; // LINT +class C { + int _x = 5; + + int get x => _x; + + set x(int x) { + _x = x; + _customUpdateLogic(); + } + + void _customUpdateLogic() { + print('updated'); + } + + void example() { + x = x; + } } ``` **GOOD:** ```dart -void throwArgumentError() { - Error error = ArgumentError('oh!'); - throw error; // OK +class C { + int _x = 5; + + int get x => _x; + + set x(int x) { + _x = x; + _customUpdateLogic(); + } + + void _customUpdateLogic() { + print('updated'); + } + + void example() { + _customUpdateLogic(); + } } ``` + +**BAD:** +```dart +class C { + int x = 5; + + void update(C other) { + this.x = this.x; + } +} +``` + +**GOOD:** +```dart +class C { + int x = 5; + + void update(C other) { + this.x = other.x; + } +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1025.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1025.md index 16f9ecee..1a471c61 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1025.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1025.md @@ -1,45 +1,38 @@ --- -title: "Avoid final for parameter declarations." -verbose_name: "avoid_final_parameters" -category: "antipattern" +title: "Don't use wildcard parameters or variables" +verbose_name: "no_wildcard_variable_uses" +category: "bug-risk" weight: 70 severity: "major" --- -**AVOID** declaring parameters as final. +**DON'T** use wildcard parameters or variables. + +Wildcard parameters and local variables +(e.g. underscore-only names like `_`, `__`, `___`, etc.) will +become non-binding in a future version of the Dart language. +Any existing code that uses wildcard parameters or variables will +break. In anticipation of this change, and to make adoption easier, +this lint disallows wildcard and variable parameter uses. -Declaring parameters as final can lead to unnecessarily verbose code, especially -when using the "parameter_assignments" rule. **BAD:** ```dart -void goodParameter(final String label) { // LINT - print(label); -} +var _ = 1; +print(_); // LINT ``` -**GOOD:** ```dart -void badParameter(String label) { // OK - print(label); +void f(int __) { + print(__); // LINT multiple underscores too } ``` -**BAD:** -```dart -void goodExpression(final int value) => print(value); // LINT -``` - **GOOD:** ```dart -void badExpression(int value) => print(value); // OK +for (var _ in [1, 2, 3]) count++; ``` -**BAD:** ```dart -[1, 4, 6, 8].forEach((final value) => print(value + 2)); // LINT +var [a, _, b, _] = [1, 2, 3, 4]; ``` -**GOOD:** -```dart -[1, 4, 6, 8].forEach((value) => print(value + 2)); // OK -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1026.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1026.md index f47374da..e1e5b59b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1026.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1026.md @@ -1,31 +1,25 @@ --- -title: "Prefer asserts with message." -verbose_name: "prefer_asserts_with_message" -category: "antipattern" +title: "Prefer relative imports for files in `lib/`" +verbose_name: "prefer_relative_imports" +category: "bug-risk" weight: 70 severity: "major" --- -When assertions fail it's not always simple to understand why. Adding a message -to the `assert` helps the developer to understand why the AssertionError occurs. +**PREFER** relative imports for files in `lib/`. + +When mixing relative and absolute imports it's possible to create confusion +where the same member gets imported in two different ways. One way to avoid +that is to ensure you consistently use relative imports for files within the +`lib/` directory. **BAD:** ```dart -f(a) { - assert(a != null); -} - -class A { - A(a) : assert(a != null); -} +import 'package:my_package/bar.dart'; ``` **GOOD:** ```dart -f(a) { - assert(a != null, 'a must not be null'); -} - -class A { - A(a) : assert(a != null, 'a must not be null'); -} +import 'bar.dart'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1027.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1027.md index e45264fc..007aaf1e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1027.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1027.md @@ -1,19 +1,39 @@ --- -title: "Prefer using if null operators." -verbose_name: "prefer_if_null_operators" -category: "antipattern" +title: "Don't use the Null type, unless you are positive that you don't want void" +verbose_name: "prefer_void_to_null" +category: "bug-risk" weight: 70 severity: "major" --- -**PREFER** using if null operators instead of null checks in conditional -expressions. +**DON'T** use the type Null where void would work. **BAD:** ```dart -v = a == null ? b : a; +Null f() {} +Future f() {} +Stream f() {} +f(Null x) {} ``` **GOOD:** ```dart -v = a ?? b; +void f() {} +Future f() {} +Stream f() {} +f(void x) {} ``` + +Some exceptions include formulating special function types: + +```dart +Null Function(Null, Null); +``` + +and for making empty literals which are safe to pass into read-only locations +for any type of map or list: + +```dart +[]; +{}; +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1028.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1028.md index 385702a9..ed31737f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1028.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1028.md @@ -1,119 +1,63 @@ --- -title: "Equality operator `==` invocation with references of unrelated types." -verbose_name: "unrelated_type_equality_checks" +title: "Test type arguments in operator ==(Object other)" +verbose_name: "test_types_in_equals" category: "bug-risk" weight: 70 severity: "major" --- -**DON'T** Compare references of unrelated types for equality. +**DO** test type arguments in operator ==(Object other). -Comparing references of a type where neither is a subtype of the other most -likely will return `false` and might not reflect programmer's intent. - -`Int64` and `Int32` from `package:fixnum` allow comparing to `int` provided -the `int` is on the right hand side. The lint allows this as a special case. - -**BAD:** -```dart -void someFunction() { - var x = '1'; - if (x == 1) print('someFunction'); // LINT -} -``` - -**BAD:** -```dart -void someFunction1() { - String x = '1'; - if (x == 1) print('someFunction1'); // LINT -} -``` +Not testing types might result in null pointer exceptions which will be +unexpected for consumers of your class. **BAD:** ```dart -void someFunction13(DerivedClass2 instance) { - var other = DerivedClass3(); - - if (other == instance) print('someFunction13'); // LINT +class Field { } -class ClassBase {} - -class DerivedClass1 extends ClassBase {} - -abstract class Mixin {} +class Bad { + final Field someField; -class DerivedClass2 extends ClassBase with Mixin {} + Bad(this.someField); -class DerivedClass3 extends ClassBase implements Mixin {} -``` - -**GOOD:** -```dart -void someFunction2() { - var x = '1'; - var y = '2'; - if (x == y) print(someFunction2); // OK -} -``` + @override + bool operator ==(Object other) { + Bad otherBad = other as Bad; // LINT + bool areEqual = otherBad != null && otherBad.someField == someField; + return areEqual; + } -**GOOD:** -```dart -void someFunction3() { - for (var i = 0; i < 10; i++) { - if (i == 0) print(someFunction3); // OK + @override + int get hashCode { + return someField.hashCode; } } ``` **GOOD:** ```dart -void someFunction4() { - var x = '1'; - if (x == null) print(someFunction4); // OK +class Field { } -``` -**GOOD:** -```dart -void someFunction7() { - List someList; +class Good { + final Field someField; - if (someList.length == 0) print('someFunction7'); // OK -} -``` + Good(this.someField); -**GOOD:** -```dart -void someFunction8(ClassBase instance) { - DerivedClass1 other; - - if (other == instance) print('someFunction8'); // OK -} -``` + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + return other is Good && + this.someField == other.someField; + } -**GOOD:** -```dart -void someFunction10(unknown) { - var what = unknown - 1; - for (var index = 0; index < unknown; index++) { - if (what == index) print('someFunction10'); // OK + @override + int get hashCode { + return someField.hashCode; } } ``` -**GOOD:** -```dart -void someFunction11(Mixin instance) { - var other = DerivedClass2(); - - if (other == instance) print('someFunction11'); // OK - if (other != instance) print('!someFunction11'); // OK -} - -class ClassBase {} -abstract class Mixin {} - -class DerivedClass2 extends ClassBase with Mixin {} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1029.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1029.md index fb087a24..5186a776 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1029.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1029.md @@ -1,117 +1,43 @@ --- -title: "Invocation of `remove` with references of unrelated types." -verbose_name: "list_remove_unrelated_type" +title: "Avoid `throw` in finally block" +verbose_name: "throw_in_finally" category: "bug-risk" weight: 70 severity: "major" --- -**DON'T** invoke `remove` on `List` with an instance of different type than -the parameter type. +**AVOID** throwing exceptions in finally blocks. -Doing this will invoke `==` on its elements and most likely will -return `false`. +Throwing exceptions in finally blocks will inevitably cause unexpected behavior +that is hard to debug. **BAD:** ```dart -void someFunction() { - var list = []; - if (list.remove('1')) print('someFunction'); // LINT +class BadThrow { + double nonCompliantMethod() { + try { + print('hello world! ${1 / 0}'); + } catch (e) { + print(e); + } finally { + throw 'Find the hidden error :P'; // LINT + } + } } ``` -**BAD:** -```dart -void someFunction3() { - List list = []; - if (list.remove('1')) print('someFunction3'); // LINT -} -``` - -**BAD:** -```dart -void someFunction8() { - List list = []; - DerivedClass3 instance; - if (list.remove(instance)) print('someFunction8'); // LINT -} -``` - -**BAD:** -```dart -abstract class SomeList implements List {} - -abstract class MyClass implements SomeList { - bool badMethod(String thing) => this.remove(thing); // LINT -} -``` - -**GOOD:** -```dart -void someFunction10() { - var list = []; - if (list.remove(1)) print('someFunction10'); // OK -} -``` - -**GOOD:** -```dart -void someFunction1() { - var list = []; - if (list.remove(1)) print('someFunction1'); // OK -} -``` - -**GOOD:** -```dart -void someFunction4() { - List list = []; - if (list.remove(1)) print('someFunction4'); // OK -} -``` - -**GOOD:** -```dart -void someFunction5() { - List list = []; - DerivedClass1 instance; - if (list.remove(instance)) print('someFunction5'); // OK -} - -abstract class ClassBase {} - -class DerivedClass1 extends ClassBase {} -``` - **GOOD:** ```dart -void someFunction6() { - List list = []; - DerivedClass2 instance; - if (list.remove(instance)) print('someFunction6'); // OK +class Ok { + double compliantMethod() { + var i = 5; + try { + i = 1 / 0; + } catch (e) { + print(e); // OK + } + return i; + } } - -abstract class ClassBase {} - -abstract class Mixin {} - -class DerivedClass2 extends ClassBase with Mixin {} ``` -**GOOD:** -```dart -void someFunction7() { - List list = []; - DerivedClass3 instance; - if (list.remove(instance)) print('someFunction7'); // OK -} - -abstract class ClassBase {} - -abstract class Mixin {} - -class DerivedClass3 extends ClassBase implements Mixin {} -``` -**DEPRECATED:** This rule is deprecated in favor of -`collection_methods_unrelated_type`. -The rule will be removed in a future Dart release. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1030.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1030.md index 63b9fff7..0f9db6cb 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1030.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1030.md @@ -1,36 +1,39 @@ --- -title: "Avoid defining a class that contains only static members." -verbose_name: "avoid_classes_with_only_static_members" -category: "antipattern" +title: "Avoid using unnecessary statements" +verbose_name: "unnecessary_statements" +category: "bug-risk" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-a-class-that-contains-only-static-members): +**AVOID** using unnecessary statements. -**AVOID** defining a class that contains only static members. +Statements which have no clear effect are usually unnecessary, or should be +broken up. -Creating classes with the sole purpose of providing utility or otherwise static -methods is discouraged. Dart allows functions to exist outside of classes for -this very reason. +For example, **BAD:** ```dart -class DateUtils { - static DateTime mostRecent(List dates) { - return dates.reduce((a, b) => a.isAfter(b) ? a : b); - } -} - -class _Favorites { - static const mammal = 'weasel'; -} +myvar; +list.clear; +1 + 2; +methodOne() + methodTwo(); +foo ? bar : baz; ``` +Though the added methods have a clear effect, the addition itself does not +unless there is some magical overload of the + operator. + +Usually code like this indicates an incomplete thought, and is a bug. + **GOOD:** ```dart -DateTime mostRecent(List dates) { - return dates.reduce((a, b) => a.isAfter(b) ? a : b); -} - -const _favoriteMammal = 'weasel'; +some.method(); +const SomeClass(); +methodOne(); +methodTwo(); +foo ? bar() : baz(); +return myvar; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1031.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1031.md index f32f164b..d8008d3f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1031.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1031.md @@ -1,55 +1,121 @@ --- -title: "Prefer final for parameter declarations if they are not reassigned." -verbose_name: "prefer_final_parameters" -category: "antipattern" +title: "Equality operator `==` invocation with references of unrelated types" +verbose_name: "unrelated_type_equality_checks" +category: "bug-risk" weight: 70 severity: "major" --- -**DO** prefer declaring parameters as final if they are not reassigned in -the function body. +**DON'T** Compare references of unrelated types for equality. -Declaring parameters as final when possible is a good practice because it helps -avoid accidental reassignments. +Comparing references of a type where neither is a subtype of the other most +likely will return `false` and might not reflect programmer's intent. + +`Int64` and `Int32` from `package:fixnum` allow comparing to `int` provided +the `int` is on the right hand side. The lint allows this as a special case. **BAD:** ```dart -void badParameter(String label) { // LINT - print(label); +void someFunction() { + var x = '1'; + if (x == 1) print('someFunction'); // LINT } ``` -**GOOD:** +**BAD:** ```dart -void goodParameter(final String label) { // OK - print(label); +void someFunction1() { + String x = '1'; + if (x == 1) print('someFunction1'); // LINT } ``` **BAD:** ```dart -void badExpression(int value) => print(value); // LINT +void someFunction13(DerivedClass2 instance) { + var other = DerivedClass3(); + + if (other == instance) print('someFunction13'); // LINT +} + +class ClassBase {} + +class DerivedClass1 extends ClassBase {} + +abstract class Mixin {} + +class DerivedClass2 extends ClassBase with Mixin {} + +class DerivedClass3 extends ClassBase implements Mixin {} ``` **GOOD:** ```dart -void goodExpression(final int value) => print(value); // OK +void someFunction2() { + var x = '1'; + var y = '2'; + if (x == y) print(someFunction2); // OK +} ``` -**BAD:** +**GOOD:** +```dart +void someFunction3() { + for (var i = 0; i < 10; i++) { + if (i == 0) print(someFunction3); // OK + } +} +``` + +**GOOD:** +```dart +void someFunction4() { + var x = '1'; + if (x == null) print(someFunction4); // OK +} +``` + +**GOOD:** ```dart -[1, 4, 6, 8].forEach((value) => print(value + 2)); // LINT +void someFunction7() { + List someList; + + if (someList.length == 0) print('someFunction7'); // OK +} ``` **GOOD:** ```dart -[1, 4, 6, 8].forEach((final value) => print(value + 2)); // OK +void someFunction8(ClassBase instance) { + DerivedClass1 other; + + if (other == instance) print('someFunction8'); // OK +} ``` **GOOD:** ```dart -void mutableParameter(String label) { // OK - print(label); - label = 'Hello Linter!'; - print(label); +void someFunction10(unknown) { + var what = unknown - 1; + for (var index = 0; index < unknown; index++) { + if (what == index) print('someFunction10'); // OK + } } ``` + +**GOOD:** +```dart +void someFunction11(Mixin instance) { + var other = DerivedClass2(); + + if (other == instance) print('someFunction11'); // OK + if (other != instance) print('!someFunction11'); // OK +} + +class ClassBase {} + +abstract class Mixin {} + +class DerivedClass2 extends ClassBase with Mixin {} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1032.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1032.md index 1544e545..e8afd764 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1032.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1032.md @@ -1,36 +1,25 @@ --- -title: "Don't invoke asynchronous functions in non-async blocks." -verbose_name: "discarded_futures" +title: "Avoid unsafe HTML APIs" +verbose_name: "unsafe_html" category: "bug-risk" weight: 70 severity: "major" --- -Making asynchronous calls in non-`async` functions is usually the sign of a -programming error. In general these functions should be marked `async` and such -futures should likely be awaited (as enforced by `unawaited_futures`). +**AVOID** + +* assigning directly to the `href` field of an AnchorElement +* assigning directly to the `src` field of an EmbedElement, IFrameElement, or + ScriptElement +* assigning directly to the `srcdoc` field of an IFrameElement +* calling the `createFragment` method of Element +* calling the `open` method of Window +* calling the `setInnerHtml` method of Element +* calling the `Element.html` constructor +* calling the `DocumentFragment.html` constructor -**DON'T** invoke asynchronous functions in non-`async` blocks. **BAD:** ```dart -void recreateDir(String path) { - deleteDir(path); - createDir(path); -} - -Future deleteDir(String path) async {} - -Future createDir(String path) async {} +var script = ScriptElement()..src = 'foo.js'; ``` -**GOOD:** -```dart -Future recreateDir(String path) async { - await deleteDir(path); - await createDir(path); -} - -Future deleteDir(String path) async {} - -Future createDir(String path) async {} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1033.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1033.md index ad6b02a9..38b30fe6 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1033.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1033.md @@ -1,32 +1,41 @@ --- -title: "Avoid using private types in public APIs." -verbose_name: "library_private_types_in_public_api" -category: "antipattern" +title: "Do not use BuildContexts across async gaps" +verbose_name: "use_build_context_synchronously" +category: "bug-risk" weight: 70 severity: "major" --- -**AVOID** using library private types in public APIs. +**DON'T** use BuildContext across asynchronous gaps. -For the purposes of this lint, a public API is considered to be any top-level or -member declaration unless the declaration is library private or contained in a -declaration that's library private. The following uses of types are checked: +Storing `BuildContext` for later usage can easily lead to difficult to diagnose +crashes. Asynchronous gaps are implicitly storing `BuildContext` and are some of +the easiest to overlook when writing code. -- the return type of a function or method, -- the type of any parameter of a function or method, -- the bound of a type parameter to any function, method, class, mixin, - extension's extended type, or type alias, -- the type of any top level variable or field, -- any type used in the declaration of a type alias (for example - `typedef F = _Private Function();`), or -- any type used in the `on` clause of an extension or a mixin +When a `BuildContext` is used, its `mounted` property must be checked after an +asynchronous gap. **BAD:** ```dart -f(_Private p) { ... } -class _Private {} +void onButtonTapped(BuildContext context) async { + await Future.delayed(const Duration(seconds: 1)); + Navigator.of(context).pop(); +} ``` **GOOD:** ```dart -f(String s) { ... } +void onButtonTapped(BuildContext context) { + Navigator.of(context).pop(); +} ``` + +**GOOD:** +```dart +void onButtonTapped() async { + await Future.delayed(const Duration(seconds: 1)); + + if (!context.mounted) return; + Navigator.of(context).pop(); +} +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1034.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1034.md index 668b4572..4d0a6613 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1034.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1034.md @@ -1,19 +1,25 @@ --- -title: "Prefer using null aware operators." -verbose_name: "prefer_null_aware_operators" -category: "antipattern" +title: "Use key in widget constructors" +verbose_name: "use_key_in_widget_constructors" +category: "bug-risk" weight: 70 severity: "major" --- -**PREFER** using null aware operators instead of null checks in conditional -expressions. +**DO** use key in widget constructors. + +It's a good practice to expose the ability to provide a key when creating public +widgets. **BAD:** ```dart -v = a == null ? null : a.b; +class MyPublicWidget extends StatelessWidget { +} ``` **GOOD:** ```dart -v = a?.b; +class MyPublicWidget extends StatelessWidget { + MyPublicWidget({super.key}); +} ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1035.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1035.md index 487e3df7..490b5aa2 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1035.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1035.md @@ -1,33 +1,24 @@ --- -title: "Don't use null check on a potentially nullable type parameter." -verbose_name: "null_check_on_nullable_type_parameter" -category: "antipattern" +title: "Use valid regular expression syntax" +verbose_name: "valid_regexps" +category: "bug-risk" weight: 70 severity: "major" --- -**DON'T** use null check on a potentially nullable type parameter. +**DO** use valid regular expression syntax when creating regular expression +instances. -Given a generic type parameter `T` which has a nullable bound (e.g. the default -bound of `Object?`), it is very easy to introduce erroneous null checks when -working with a variable of type `T?`. Specifically, it is not uncommon to have -`T? x;` and want to assert that `x` has been set to a valid value of type `T`. -A common mistake is to do so using `x!`. This is almost always incorrect, since -if `T` is a nullable type, `x` may validly hold `null` as a value of type `T`. +Regular expressions created with invalid syntax will throw a `FormatException` +at runtime so should be avoided. **BAD:** ```dart -T run(T callback()) { - T? result; - (() { result = callback(); })(); - return result!; -} +print(RegExp(r'(').hasMatch('foo()')); ``` **GOOD:** ```dart -T run(T callback()) { - T? result; - (() { result = callback(); })(); - return result as T; -} +print(RegExp(r'\(').hasMatch('foo()')); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1036.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1036.md index 46383972..a7f59f6b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1036.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1036.md @@ -1,37 +1,39 @@ --- -title: "Tighten type of initializing formal." -verbose_name: "tighten_type_of_initializing_formals" +title: "Depend on referenced packages" +verbose_name: "depend_on_referenced_packages" category: "antipattern" weight: 70 severity: "major" --- -Tighten the type of an initializing formal if a non-null assert exists. This -allows the type system to catch problems rather than have them only be caught at -run-time. +**DO** depend on referenced packages. + +When importing a package, add a dependency on it to your pubspec. + +Depending explicitly on packages that you reference ensures they will always +exist and allows you to put a dependency constraint on them to guard you +against breaking changes. + +Whether this should be a regular dependency or dev_dependency depends on if it +is referenced from a public file (one under either `lib` or `bin`), or some +other private file. **BAD:** ```dart -class A { - A.c1(this.p) : assert(p != null); - A.c2(this.p); - final String? p; -} +import 'package:a/a.dart'; +``` + +```yaml +dependencies: ``` **GOOD:** ```dart -class A { - A.c1(String this.p); - A.c2(this.p); - final String? p; -} - -class B { - String? b; - B(this.b); -} - -class C extends B { - B(String super.b); -} +import 'package:a/a.dart'; ``` + +```yaml +dependencies: + a: ^1.0.0 +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1037.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1037.md index 14936a59..f7b83e90 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1037.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1037.md @@ -1,41 +1,17 @@ --- -title: "Avoid slow async `dart:io` methods." -verbose_name: "avoid_slow_async_io" -category: "bug-risk" +title: "Use `lowercase_with_underscores` for package names" +verbose_name: "package_names" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using the following asynchronous file I/O methods because they are -much slower than their synchronous counterparts. +From the [Pubspec format description](https://dart.dev/tools/pub/pubspec): -* `Directory.exists` -* `Directory.stat` -* `File.lastModified` -* `File.exists` -* `File.stat` -* `FileSystemEntity.isDirectory` -* `FileSystemEntity.isFile` -* `FileSystemEntity.isLink` -* `FileSystemEntity.type` +**DO** use `lowercase_with_underscores` for package names. -**BAD:** -```dart -import 'dart:io'; +Package names should be all lowercase, with underscores to separate words, +`just_like_this`. Use only basic Latin letters and Arabic digits: [a-z0-9_]. +Also, make sure the name is a valid Dart identifier -- that it doesn't start +with digits and isn't a reserved word. -Future someFunction() async { - var file = File('/path/to/my/file'); - var now = DateTime.now(); - if ((await file.lastModified()).isBefore(now)) print('before'); // LINT -} -``` -**GOOD:** -```dart -import 'dart:io'; - -Future someFunction() async { - var file = File('/path/to/my/file'); - var now = DateTime.now(); - if (file.lastModifiedSync().isBefore(now)) print('before'); // OK -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1038.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1038.md index cd627594..7299374f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1038.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1038.md @@ -1,39 +1,27 @@ --- -title: "Don't override a method to do a super method invocation with the same r' parameters." -verbose_name: "unnecessary_overrides" +title: "Use secure urls in `pubspec.yaml`" +verbose_name: "secure_pubspec_urls" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** override a method to do a super method invocation with same parameters. +**DO** Use secure urls in `pubspec.yaml`. + +Use `https` instead of `http` or `git:`. **BAD:** -```dart -class A extends B { - @override - void foo() { - super.foo(); - } -} +```yaml +repository: http://github.com/dart-lang/example ``` -**GOOD:** -```dart -class A extends B { - @override - void foo() { - doSomethingElse(); - } -} +```yaml +git: + url: git://github.com/dart-lang/example/example.git ``` -It's valid to override a member in the following cases: +**GOOD:** +```yaml +repository: https://github.com/dart-lang/example +``` -* if a type (return type or a parameter type) is not the exactly the same as the - super member, -* if the `covariant` keyword is added to one of the parameters, -* if documentation comments are present on the member, -* if the member has annotations other than `@override`, -* if the member is not annotated with `@protected`, and the super member is. -`noSuchMethod` is a special method and is not checked by this rule. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1039.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1039.md index 8a271eff..fc51a0cf 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1039.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1039.md @@ -1,22 +1,11 @@ --- -title: "Inline list item declarations where possible." -verbose_name: "prefer_inlined_adds" +title: "Sort pub dependencies alphabetically" +verbose_name: "sort_pub_dependencies" category: "antipattern" weight: 70 severity: "major" --- -Declare elements in list literals inline, rather than using `add` and -`addAll` methods where possible. +**DO** sort pub dependencies alphabetically (A to Z) in `pubspec.yaml`. +Sorting list of pub dependencies makes maintenance easier. -**BAD:** -```dart -var l = ['a']..add('b')..add('c'); -var l2 = ['a']..addAll(['b', 'c']); -``` - -**GOOD:** -```dart -var l = ['a', 'b', 'c']; -var l2 = ['a', 'b', 'c']; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1040.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1040.md index d86de295..336d2ea9 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1040.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1040.md @@ -1,27 +1,39 @@ --- -title: "Noop primitive operations." -verbose_name: "noop_primitive_operations" +title: "Declare method return types" +verbose_name: "always_declare_return_types" category: "antipattern" weight: 70 severity: "major" --- -Some operations on primitive types are idempotent and can be removed. +**DO** declare method return types. + +When declaring a method or function *always* specify a return type. +Declaring return types for functions helps improve your codebase by allowing the +analyzer to more adequately check your code for errors that could occur during +runtime. **BAD:** +```dart +main() { } +_bar() => _Foo(); + +class _Foo { + _foo() => 42; +} +``` + +**GOOD:** ```dart -doubleValue.toDouble(); +void main() { } -intValue.toInt(); -intValue.round(); -intValue.ceil(); -intValue.floor(); -intValue.truncate(); +_Foo _bar() => _Foo(); -string.toString(); -string = 'hello\n' - 'world\n' - ''; // useless empty string +class _Foo { + int _foo() => 42; +} -'string with ${x.toString()}'; +typedef predicate = bool Function(Object o); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1041.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1041.md index 12c4846e..efb6e6f4 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1041.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1041.md @@ -1,22 +1,45 @@ --- -title: "Avoid using `null` in `if null` operators." -verbose_name: "unnecessary_null_in_if_null_operators" +title: "Separate the control structure expression from its statement" +verbose_name: "always_put_control_body_on_new_line" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using `null` as an operand in `if null` operators. +From the [style guide for the flutter repo](https://flutter.dev/style-guide/): -Using `null` in an `if null` operator is redundant, regardless of which side -`null` is used on. +**DO** separate the control structure expression from its statement. + +Don't put the statement part of an `if`, `for`, `while`, `do` on the same line +as the expression, even if it is short. Doing so makes it unclear that there +is relevant code there. This is especially important for early returns. **BAD:** ```dart -var x = a ?? null; -var y = null ?? 1; +if (notReady) return; + +if (notReady) + return; +else print('ok') + +while (condition) i += 1; ``` **GOOD:** ```dart -var x = a ?? 1; +if (notReady) + return; + +if (notReady) + return; +else + print('ok') + +while (condition) + i += 1; ``` + +Note that this rule can conflict with the +[Dart formatter](https://dart.dev/tools/dart-format), and should not be enabled +when the Dart formatter is used. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1042.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1042.md index 405011fe..e0e8dc96 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1042.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1042.md @@ -1,16 +1,30 @@ --- -title: "Avoid empty else statements." -verbose_name: "avoid_empty_else" -category: "bug-risk" +title: "Put required named parameters first" +verbose_name: "always_put_required_named_parameters_first" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** empty else statements. +**DO** specify `required` on named parameter before other named parameters. **BAD:** ```dart -if (x > y) - print("1"); -else ; - print("2"); +m({b, c, required a}) ; ``` + +**GOOD:** +```dart +m({required a, b, c}) ; +``` + +**BAD:** +```dart +m({b, c, @required a}) ; +``` + +**GOOD:** +```dart +m({@required a, b, c}) ; +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1043.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1043.md index 8607735c..25b8eafb 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1043.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1043.md @@ -1,39 +1,51 @@ --- -title: "No default cases." -verbose_name: "no_default_cases" +title: "Specify type annotations" +verbose_name: "always_specify_types" category: "antipattern" weight: 70 severity: "major" --- -Switches on enums and enum-like classes should not use a `default` clause. +From the [style guide for the flutter repo](https://flutter.dev/style-guide/): -Enum-like classes are defined as concrete (non-abstract) classes that have: - * only private non-factory constructors - * two or more static const fields whose type is the enclosing class and - * no subclasses of the class in the defining library +**DO** specify type annotations. -**DO** define default behavior outside switch statements. +Avoid `var` when specifying that a type is unknown and short-hands that elide +type annotations. Use `dynamic` if you are being explicit that the type is +unknown. Use `Object` if you are being explicit that you want an object that +implements `==` and `hashCode`. **BAD:** ```dart - switch (testEnum) { - case TestEnum.A: - return '123'; - case TestEnum.B: - return 'abc'; - default: - return null; - } +var foo = 10; +final bar = Bar(); +const quux = 20; ``` **GOOD:** ```dart - switch (testEnum) { - case TestEnum.A: - return '123'; - case TestEnum.B: - return 'abc'; - } - // Default here. - return null; +int foo = 10; +final Bar bar = Bar(); +String baz = 'hello'; +const int quux = 20; ``` + +NOTE: Using the the `@optionalTypeArgs` annotation in the `meta` package, API +authors can special-case type variables whose type needs to by dynamic but whose +declaration should be treated as optional. For example, suppose you have a +`Key` object whose type parameter you'd like to treat as optional. Using the +`@optionalTypeArgs` would look like this: + +```dart +import 'package:meta/meta.dart'; + +@optionalTypeArgs +class Key { + ... +} + +main() { + Key s = Key(); // OK! +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1044.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1044.md index 29b78d84..27adbabd 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1044.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1044.md @@ -1,22 +1,39 @@ --- -title: "Unnecessary toList() in spreads." -verbose_name: "unnecessary_to_list_in_spreads" +title: "Annotate overridden members" +verbose_name: "annotate_overrides" category: "antipattern" weight: 70 severity: "major" --- -Unnecessary `toList()` in spreads. +**DO** annotate overridden methods and fields. + +This practice improves code readability and helps protect against +unintentionally overriding superclass members. **BAD:** ```dart -children: [ - ...['foo', 'bar', 'baz'].map((String s) => Text(s)).toList(), -] +class Cat { + int get lives => 9; +} + +class Lucky extends Cat { + final int lives = 14; +} ``` **GOOD:** ```dart -children: [ - ...['foo', 'bar', 'baz'].map((String s) => Text(s)), -] +abstract class Dog { + String get breed; + void bark() {} +} + +class Husky extends Dog { + @override + final String breed = 'Husky'; + @override + void bark() {} +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1045.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1045.md index fc5413f3..313b9d79 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1045.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1045.md @@ -1,20 +1,31 @@ --- -title: "Unnecessary raw string." -verbose_name: "unnecessary_raw_strings" +title: "Avoid annotating with dynamic when not required" +verbose_name: "avoid_annotating_with_dynamic" category: "antipattern" weight: 70 severity: "major" --- -Use raw string only when needed. +**AVOID** annotating with dynamic when not required. + +As `dynamic` is the assumed return value of a function or method, it is usually +not necessary to annotate it. **BAD:** ```dart -var s1 = r'a'; +dynamic lookUpOrDefault(String name, Map map, dynamic defaultValue) { + var value = map[name]; + if (value != null) return value; + return defaultValue; +} ``` **GOOD:** ```dart -var s1 = 'a'; -var s2 = r'$a'; -var s3 = r'\a'; +lookUpOrDefault(String name, Map map, defaultValue) { + var value = map[name]; + if (value != null) return value; + return defaultValue; +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1046.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1046.md index e7e197b6..ff715553 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1046.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1046.md @@ -1,18 +1,26 @@ --- -title: "Use predefined named constants." -verbose_name: "use_named_constants" +title: "Avoid bool literals in conditional expressions" +verbose_name: "avoid_bool_literals_in_conditional_expressions" category: "antipattern" weight: 70 severity: "major" --- -Where possible, use already defined const values. +**AVOID** bool literals in conditional expressions. **BAD:** ```dart -const Duration(seconds: 0); +condition ? true : boolExpression +condition ? false : boolExpression +condition ? boolExpression : true +condition ? boolExpression : false ``` **GOOD:** ```dart -Duration.zero; +condition || boolExpression +!condition && boolExpression +!condition || boolExpression +condition && boolExpression ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1047.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1047.md index 9152e7d9..96b9b828 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1047.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1047.md @@ -1,18 +1,33 @@ --- -title: "Use generic function type syntax for parameters." -verbose_name: "use_function_type_syntax_for_parameters" +title: "Avoid catches without on clauses" +verbose_name: "avoid_catches_without_on_clauses" category: "antipattern" weight: 70 severity: "major" --- -Use generic function type syntax for parameters. +**AVOID** catches without on clauses. + +Using catch clauses without on clauses make your code prone to encountering +unexpected errors that won't be thrown (and thus will go unnoticed). **BAD:** ```dart -Iterable where(bool predicate(T element)) {} +try { + somethingRisky() +} +catch(e) { + doSomething(e); +} ``` **GOOD:** ```dart -Iterable where(bool Function(T) predicate) {} +try { + somethingRisky() +} +on Exception catch(e) { + doSomething(e); +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1048.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1048.md index fff7b2fc..a18c47d8 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1048.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1048.md @@ -1,33 +1,31 @@ --- -title: "`Future` results in `async` function bodies must be `await`ed or marked `unawaited` using `dart:async`." -verbose_name: "unawaited_futures" +title: "Don't explicitly catch Error or types that implement it" +verbose_name: "avoid_catching_errors" category: "antipattern" weight: 70 severity: "major" --- -**DO** await functions that return a `Future` inside of an async function body. +**DON'T** explicitly catch Error or types that implement it. -It's easy to forget await in async methods as naming conventions usually don't -tell us if a method is sync or async (except for some in `dart:io`). - -When you really _do_ want to start a fire-and-forget `Future`, the recommended -way is to use `unawaited` from `dart:async`. The `// ignore` and -`// ignore_for_file` comments also work. +Errors differ from Exceptions in that Errors can be analyzed and prevented prior +to runtime. It should almost never be necessary to catch an error at runtime. **BAD:** ```dart -void main() async { - doSomething(); // Likely a bug. +try { + somethingRisky(); +} on Error catch(e) { + doSomething(e); } ``` **GOOD:** ```dart -Future doSomething() => ...; - -void main() async { - await doSomething(); - - unawaited(doSomething()); // Explicitly-ignored fire-and-forget. +try { + somethingRisky(); +} on Exception catch(e) { + doSomething(e); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1049.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1049.md index e5d4c55a..95cd4ee4 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1049.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1049.md @@ -1,18 +1,38 @@ --- -title: "Avoid types as parameter names." -verbose_name: "avoid_types_as_parameter_names" -category: "bug-risk" +title: "Avoid defining a class that contains only static members" +verbose_name: "avoid_classes_with_only_static_members" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using a parameter name that is the same as an existing type. +From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-a-class-that-contains-only-static-members): + +**AVOID** defining a class that contains only static members. + +Creating classes with the sole purpose of providing utility or otherwise static +methods is discouraged. Dart allows functions to exist outside of classes for +this very reason. **BAD:** ```dart -m(f(int)); +class DateUtils { + static DateTime mostRecent(List dates) { + return dates.reduce((a, b) => a.isAfter(b) ? a : b); + } +} + +class _Favorites { + static const mammal = 'weasel'; +} ``` **GOOD:** ```dart -m(f(int v)); +DateTime mostRecent(List dates) { + return dates.reduce((a, b) => a.isAfter(b) ? a : b); +} + +const _favoriteMammal = 'weasel'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1050.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1050.md index 92c259b8..b93aed98 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1050.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1050.md @@ -1,37 +1,36 @@ --- -title: "Avoid using unnecessary statements." -verbose_name: "unnecessary_statements" -category: "bug-risk" +title: "Avoid double and int checks" +verbose_name: "avoid_double_and_int_checks" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using unnecessary statements. +**AVOID** to check if type is double or int. -Statements which have no clear effect are usually unnecessary, or should be -broken up. - -For example, +When compiled to JS, integer values are represented as floats. That can lead to +some unexpected behavior when using either `is` or `is!` where the type is +either `int` or `double`. **BAD:** ```dart -myvar; -list.clear; -1 + 2; -methodOne() + methodTwo(); -foo ? bar : baz; +f(num x) { + if (x is double) { + ... + } else if (x is int) { + ... + } +} ``` -Though the added methods have a clear effect, the addition itself does not -unless there is some magical overload of the + operator. - -Usually code like this indicates an incomplete thought, and is a bug. - **GOOD:** ```dart -some.method(); -const SomeClass(); -methodOne(); -methodTwo(); -foo ? bar() : baz(); -return myvar; +f(dynamic x) { + if (x is num) { + ... + } else { + ... + } +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1051.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1051.md index f0ebc754..b32e30fa 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1051.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1051.md @@ -1,24 +1,55 @@ --- -title: "Prefer putting asserts in initializer lists." -verbose_name: "prefer_asserts_in_initializer_lists" +title: "Avoid overloading operator == and hashCode on classes not marked `@immutable`" +verbose_name: "avoid_equals_and_hash_code_on_mutable_classes" category: "antipattern" weight: 70 severity: "major" --- -**DO** put asserts in initializer lists. +From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-custom-equality-for-mutable-classes): + +**AVOID** overloading operator == and hashCode on classes not marked `@immutable`. + +If a class is not immutable, overloading `operator ==` and `hashCode` can +lead to unpredictable and undesirable behavior when used in collections. **BAD:** ```dart -class A { - A(int a) { - assert(a != 0); - } +class B { + String key; + const B(this.key); + @override + operator ==(other) => other is B && other.key == key; + @override + int get hashCode => key.hashCode; } ``` **GOOD:** ```dart +@immutable class A { - A(int a) : assert(a != 0); + final String key; + const A(this.key); + @override + operator ==(other) => other is A && other.key == key; + @override + int get hashCode => key.hashCode; } ``` + +NOTE: The lint checks the use of the `@immutable` annotation, and will trigger +even if the class is otherwise not mutable. Thus: + +**BAD:** +```dart +class C { + final String key; + const C(this.key); + @override + operator ==(other) => other is C && other.key == key; + @override + int get hashCode => key.hashCode; +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1052.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1052.md index c16cc734..785119fa 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1052.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1052.md @@ -1,41 +1,20 @@ --- -title: "Avoid unnecessary containers." -verbose_name: "avoid_unnecessary_containers" +title: "Avoid escaping inner quotes by converting surrounding quotes" +verbose_name: "avoid_escaping_inner_quotes" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** wrapping widgets in unnecessary containers. - -Wrapping a widget in `Container` with no other parameters set has no effect -and makes code needlessly more complex. +Avoid escaping inner quotes by converting surrounding quotes. **BAD:** ```dart -Widget buildRow() { - return Container( - child: Row( - children: [ - const MyLogo(), - const Expanded( - child: Text('...'), - ), - ], - ) - ); -} +var s = 'It\'s not fun'; ``` **GOOD:** ```dart -Widget buildRow() { - return Row( - children: [ - const MyLogo(), - const Expanded( - child: Text('...'), - ), - ], - ); -} +var s = "It's not fun"; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1053.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1053.md index efde7fc3..35236e29 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1053.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1053.md @@ -1,26 +1,30 @@ --- -title: "Avoid const keyword." -verbose_name: "unnecessary_const" +title: "Avoid field initializers in const classes" +verbose_name: "avoid_field_initializers_in_const_classes" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** repeating const keyword in a const context. +**AVOID** field initializers in const classes. + +Instead of `final x = const expr;`, you should write `get x => const expr;` and +not allocate a useless field. As of April 2018 this is true for the VM, but not +for code that will be compiled to JS. **BAD:** ```dart -class A { const A(); } -m(){ - const a = const A(); - final b = const [const A()]; +class A { + final a = const []; + const A(); } ``` **GOOD:** ```dart -class A { const A(); } -m(){ - const a = A(); - final b = const [A()]; +class A { + get a => const []; + const A(); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1054.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1054.md index f841e7ea..160d4a01 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1054.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1054.md @@ -1,22 +1,47 @@ --- -title: "Use adjacent strings to concatenate string literals." -verbose_name: "prefer_adjacent_string_concatenation" +title: "Avoid final for parameter declarations" +verbose_name: "avoid_final_parameters" category: "antipattern" weight: 70 severity: "major" --- -**DO** use adjacent strings to concatenate string literals. +**AVOID** declaring parameters as final. + +Declaring parameters as final can lead to unnecessarily verbose code, especially +when using the "parameter_assignments" rule. + +**BAD:** +```dart +void goodParameter(final String label) { // LINT + print(label); +} +``` + +**GOOD:** +```dart +void badParameter(String label) { // OK + print(label); +} +``` **BAD:** ```dart -raiseAlarm( - 'ERROR: Parts of the spaceship are on fire. Other ' + - 'parts are overrun by martians. Unclear which are which.'); +void goodExpression(final int value) => print(value); // LINT ``` **GOOD:** ```dart -raiseAlarm( - 'ERROR: Parts of the spaceship are on fire. Other ' - 'parts are overrun by martians. Unclear which are which.'); +void badExpression(int value) => print(value); // OK ``` + +**BAD:** +```dart +[1, 4, 6, 8].forEach((final value) => print(value + 2)); // LINT +``` + +**GOOD:** +```dart +[1, 4, 6, 8].forEach((value) => print(value + 2)); // OK +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1055.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1055.md index 9ee5a309..30eb512f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1055.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1055.md @@ -1,23 +1,29 @@ --- -title: "Use contains for `List` and `String` instances." -verbose_name: "prefer_contains" +title: "Avoid using `forEach` with a function literal" +verbose_name: "avoid_function_literals_in_foreach_calls" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use `indexOf` to see if a collection contains an element. +**AVOID** using `forEach` with a function literal. -Calling `indexOf` to see if a collection contains something is difficult to read -and may have poor performance. - -Instead, prefer `contains`. +The `for` loop enables a developer to be clear and explicit as to their intent. +A return in the body of the `for` loop returns from the body of the function, +where as a return in the body of the `forEach` closure only returns a value +for that iteration of the `forEach`. The body of a `for` loop can contain +`await`s, while the closure body of a `forEach` cannot. **BAD:** ```dart -if (lunchBox.indexOf('sandwich') == -1) return 'so hungry...'; +people.forEach((person) { + ... +}); ``` **GOOD:** ```dart -if (!lunchBox.contains('sandwich')) return 'so hungry...'; +for (var person in people) { + ... +} ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1056.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1056.md index ea866e9d..50d41cd9 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1056.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1056.md @@ -1,29 +1,82 @@ --- -title: "Don't cast a nullable value to a non nullable type." -verbose_name: "cast_nullable_to_non_nullable" +title: "Don't implement classes that override `==`" +verbose_name: "avoid_implementing_value_types" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** cast a nullable value to a non nullable type. This hides a null check -and most of the time it is not what is expected. +**DON'T** implement classes that override `==`. + +The `==` operator is contractually required to be an equivalence relation; +that is, symmetrically for all objects `o1` and `o2`, `o1 == o2` and `o2 == o1` +must either both be true, or both be false. + +> _NOTE_: Dart does not have true _value types_, so instead we consider a class +> that implements `==` as a _proxy_ for identifying value types. + +When using `implements`, you do not inherit the method body of `==`, making it +nearly impossible to follow the contract of `==`. Classes that override `==` +typically are usable directly in tests _without_ creating mocks or fakes as +well. For example, for a given class `Size`: + +```dart +class Size { + final int inBytes; + const Size(this.inBytes); + + @override + bool operator ==(Object other) => other is Size && other.inBytes == inBytes; + + @override + int get hashCode => inBytes.hashCode; +} +``` + +**BAD:** +```dart +class CustomSize implements Size { + final int inBytes; + const CustomSize(this.inBytes); + + int get inKilobytes => inBytes ~/ 1000; +} +``` **BAD:** ```dart -class A {} -class B extends A {} +import 'package:test/test.dart'; +import 'size.dart'; -A? a; -var v = a as B; -var v = a as A; +class FakeSize implements Size { + int inBytes = 0; +} + +void main() { + test('should not throw on a size >1Kb', () { + expect(() => someFunction(FakeSize()..inBytes = 1001), returnsNormally); + }); +} ``` **GOOD:** ```dart -class A {} -class B extends A {} +class ExtendedSize extends Size { + ExtendedSize(int inBytes) : super(inBytes); + + int get inKilobytes => inBytes ~/ 1000; +} +``` + +**GOOD:**: +```dart +import 'package:test/test.dart'; +import 'size.dart'; -A? a; -var v = a! as B; -var v = a!; +void main() { + test('should not throw on a size >1Kb', () { + expect(() => someFunction(Size(1001)), returnsNormally); + }); +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1057.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1057.md index d45dc9e4..f8dd6297 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1057.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1057.md @@ -1,22 +1,51 @@ --- -title: "Use string in part of directives." -verbose_name: "use_string_in_part_of_directives" +title: "Don't explicitly initialize variables to null" +verbose_name: "avoid_init_to_null" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-strings-in-part-of-directives): +From [Effective Dart](https://dart.dev/effective-dart/usage#dont-explicitly-initialize-variables-to-null): -**DO** use strings in `part of` directives. +**DON'T** explicitly initialize variables to `null`. -**BAD:** +If a variable has a non-nullable type or is `final`, +Dart reports a compile error if you try to use it +before it has been definitely initialized. +If the variable is nullable and not `const` or `final`, +then it is implicitly initialized to `null` for you. +There's no concept of "uninitialized memory" in Dart +and no need to explicitly initialize a variable to `null` to be "safe". +Adding `= null` is redundant and unneeded. +**BAD:** ```dart -part of my_library; +Item? bestDeal(List cart) { + Item? bestItem = null; + + for (final item in cart) { + if (bestItem == null || item.price < bestItem.price) { + bestItem = item; + } + } + + return bestItem; +} ``` **GOOD:** - ```dart -part of '../../my_library.dart'; +Item? bestDeal(List cart) { + Item? bestItem; + + for (final item in cart) { + if (bestItem == null || item.price < bestItem.price) { + bestItem = item; + } + } + + return bestItem; +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1058.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1058.md index 4dc25870..8b3e5512 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1058.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1058.md @@ -1,40 +1,28 @@ --- -title: "Do not use BuildContexts across async gaps." -verbose_name: "use_build_context_synchronously" -category: "bug-risk" +title: "Avoid JavaScript rounded ints" +verbose_name: "avoid_js_rounded_ints" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use BuildContext across asynchronous gaps. +**AVOID** integer literals that cannot be represented exactly when compiled to +JavaScript. -Storing `BuildContext` for later usage can easily lead to difficult to diagnose -crashes. Asynchronous gaps are implicitly storing `BuildContext` and are some of -the easiest to overlook when writing code. +When a program is compiled to JavaScript `int` and `double` become JavaScript +Numbers. Too large integers (`value < Number.MIN_SAFE_INTEGER` or +`value > Number.MAX_SAFE_INTEGER`) may be rounded to the closest Number value. -When a `BuildContext` is used, its `mounted` property must be checked after an -asynchronous gap. +For instance `1000000000000000001` cannot be represented exactly as a JavaScript +Number, so `1000000000000000000` will be used instead. **BAD:** ```dart -void onButtonTapped(BuildContext context) async { - await Future.delayed(const Duration(seconds: 1)); - Navigator.of(context).pop(); -} +int value = 9007199254740995; ``` **GOOD:** ```dart -void onButtonTapped(BuildContext context) { - Navigator.of(context).pop(); -} +BigInt value = BigInt.parse('9007199254740995'); ``` -**GOOD:** -```dart -void onButtonTapped() async { - await Future.delayed(const Duration(seconds: 1)); - if (!context.mounted) return; - Navigator.of(context).pop(); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1059.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1059.md index 3c381d91..141063c6 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1059.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1059.md @@ -1,20 +1,22 @@ --- -title: "Remove unnecessary backslashes in strings." -verbose_name: "unnecessary_string_escapes" +title: "Don't declare multiple variables on a single line" +verbose_name: "avoid_multiple_declarations_per_line" category: "antipattern" weight: 70 severity: "major" --- -Remove unnecessary backslashes in strings. +**DON'T** declare multiple variables on a single line. **BAD:** ```dart -'this string contains 2 \"double quotes\" '; -"this string contains 2 \'single quotes\' "; +String? foo, bar, baz; ``` **GOOD:** ```dart -'this string contains 2 "double quotes" '; -"this string contains 2 'single quotes' "; +String? foo; +String? bar; +String? baz; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1060.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1060.md index 5b29b1f6..f8a8697a 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1060.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1060.md @@ -1,18 +1,35 @@ --- -title: "Use `=` to separate a named parameter from its default value." -verbose_name: "prefer_equal_for_default_values" +title: "Don't check for null in custom == operators" +verbose_name: "avoid_null_checks_in_equality_operators" category: "antipattern" weight: 70 severity: "major" --- -**DO** use `=` to separate a named parameter from its default value. +**DON'T** check for null in custom == operators. + +As null is a special value, no instance of any class (other than `Null`) can be +equivalent to it. Thus, it is redundant to check whether the other instance is +null. **BAD:** ```dart -m({a: 1}) +class Person { + final String? name; + + @override + operator ==(Object? other) => + other != null && other is Person && name == other.name; +} ``` **GOOD:** ```dart -m({a = 1}) +class Person { + final String? name; + + @override + operator ==(Object? other) => other is Person && name == other.name; +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1061.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1061.md index 66fb847d..905b1730 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1061.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1061.md @@ -1,20 +1,30 @@ --- -title: "Don't create a lambda when a tear-off will do." -verbose_name: "unnecessary_lambdas" +title: "Avoid positional boolean parameters" +verbose_name: "avoid_positional_boolean_parameters" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** create a lambda when a tear-off will do. +**AVOID** positional boolean parameters. + +Positional boolean parameters are a bad practice because they are very +ambiguous. Using named boolean parameters is much more readable because it +inherently describes what the boolean value represents. **BAD:** ```dart -names.forEach((name) { - print(name); -}); +Task(true); +Task(false); +ListBox(false, true, true); +Button(false); ``` **GOOD:** ```dart -names.forEach(print); +Task.oneShot(); +Task.repeating(); +ListBox(scroll: true, showScrollbars: true); +Button(ButtonState.enabled); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1062.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1062.md index b8346801..17185795 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1062.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1062.md @@ -1,22 +1,22 @@ --- -title: "Avoid annotating types for function expression parameters." -verbose_name: "avoid_types_on_closure_parameters" +title: "Avoid private typedef functions" +verbose_name: "avoid_private_typedef_functions" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** annotating types for function expression parameters. - -Annotating types for function expression parameters is usually unnecessary -because the parameter types can almost always be inferred from the context, -thus making the practice redundant. +**AVOID** private typedef functions used only once. Prefer inline function +syntax. **BAD:** ```dart -var names = people.map((Person person) => person.name); +typedef void _F(); +m(_F f); ``` **GOOD:** ```dart -var names = people.map((person) => person.name); +m(void Function() f); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1063.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1063.md index e36cd224..90caf46c 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1063.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1063.md @@ -1,19 +1,33 @@ --- -title: "Use a non-nullable type for a final variable initialized with a non-nullable value." -verbose_name: "unnecessary_nullable_for_final_variable_declarations" +title: "Avoid redundant argument values" +verbose_name: "avoid_redundant_argument_values" category: "antipattern" weight: 70 severity: "major" --- -Use a non-nullable type for a final variable initialized with a non-nullable +**DON'T** pass an argument that matches the corresponding parameter's default value. **BAD:** ```dart -final int? i = 1; +void f({bool valWithDefault = true, bool? val}) { + ... +} + +void main() { + f(valWithDefault: true); +} ``` **GOOD:** ```dart -final int i = 1; +void f({bool valWithDefault = true, bool? val}) { + ... +} + +void main() { + f(valWithDefault: false); + f(); +} ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1064.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1064.md index 8635b922..5bda7bd8 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1064.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1064.md @@ -1,20 +1,37 @@ --- -title: "Unnecessary string interpolation." -verbose_name: "unnecessary_string_interpolations" +title: "Don't rename parameters of overridden methods" +verbose_name: "avoid_renaming_method_parameters" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use string interpolation if there's only a string expression in it. +**DON'T** rename parameters of overridden methods. + +Methods that override another method, but do not have their own documentation +comment, will inherit the overridden method's comment when `dart doc` produces +documentation. If the inherited method contains the name of the parameter (in +square brackets), then `dart doc` cannot link it correctly. **BAD:** ```dart -String message; -String o = '$message'; +abstract class A { + m(a); +} + +abstract class B extends A { + m(b); +} ``` **GOOD:** ```dart -String message; -String o = message; +abstract class A { + m(a); +} + +abstract class B extends A { + m(a); +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1065.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1065.md index 9225d80c..fbddf3b7 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1065.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1065.md @@ -1,41 +1,22 @@ --- -title: "Avoid .toString() in production code since results may be minified." -verbose_name: "avoid_type_to_string" -category: "bug-risk" +title: "Avoid return types on setters" +verbose_name: "avoid_return_types_on_setters" +category: "antipattern" weight: 70 severity: "major" --- -**DO** avoid calls to .toString() in production code, since it does not -contractually return the user-defined name of the Type (or underlying class). -Development-mode compilers where code size is not a concern use the full name, -but release-mode compilers often choose to minify these symbols. +**AVOID** return types on setters. + +As setters do not return a value, declaring the return type of one is redundant. **BAD:** ```dart -void bar(Object other) { - if (other.runtimeType.toString() == 'Bar') { - doThing(); - } -} - -Object baz(Thing myThing) { - return getThingFromDatabase(key: myThing.runtimeType.toString()); -} +void set speed(int ms); ``` **GOOD:** ```dart -void bar(Object other) { - if (other is Bar) { - doThing(); - } -} +set speed(int ms); +``` -class Thing { - String get thingTypeKey => ... -} -Object baz(Thing myThing) { - return getThingFromDatabase(key: myThing.thingTypeKey); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1066.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1066.md index 57f030ad..528d66da 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1066.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1066.md @@ -1,28 +1,36 @@ --- -title: "Don't compare booleans to boolean literals." -verbose_name: "no_literal_bool_comparisons" +title: "Avoid returning null for void" +verbose_name: "avoid_returning_null_for_void" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-true-or-false-in-equality-operations): +**AVOID** returning null for void. -**DON'T** use `true` or `false` in equality operations. - -This lint applies only if the expression is of a non-nullable `bool` type. +In a large variety of languages `void` as return type is used to indicate that +a function doesn't return anything. Dart allows returning `null` in functions +with `void` return type but it also allow using `return;` without specifying any +value. To have a consistent way you should not return `null` and only use an +empty return. **BAD:** ```dart -if (someBool == true) { +void f1() { + return null; } -while (someBool == false) { +Future f2() async { + return null; } ``` **GOOD:** ```dart -if (someBool) { +void f1() { + return; } -while (!someBool) { +Future f2() async { + return; } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1067.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1067.md index 0aaa20f3..a15b51c5 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1067.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1067.md @@ -1,35 +1,36 @@ --- -title: "Name source files using `lowercase_with_underscores`." -verbose_name: "file_names" +title: "Avoid returning this from methods just to enable a fluent interface" +verbose_name: "avoid_returning_this" category: "antipattern" weight: 70 severity: "major" --- -**DO** name source files using `lowercase_with_underscores`. +**AVOID** returning this from methods just to enable a fluent interface. -Some file systems are not case-sensitive, so many projects require filenames to -be all lowercase. Using a separating character allows names to still be readable -in that form. Using underscores as the separator ensures that the name is still -a valid Dart identifier, which may be helpful if the language later supports -symbolic imports. +Returning `this` from a method is redundant; Dart has a cascade operator which +allows method chaining universally. -**BAD:** - -* `SliderMenu.dart` -* `filesystem.dart` -* `file-system.dart` - -**GOOD:** +Returning `this` is allowed for: -* `slider_menu.dart` -* `file_system.dart` +- operators +- methods with a return type different of the current class +- methods defined in parent classes / mixins or interfaces +- methods defined in extensions -Files without a strict `.dart` extension are ignored. For example: +**BAD:** +```dart +var buffer = StringBuffer() + .write('one') + .write('two') + .write('three'); +``` -**OK:** +**GOOD:** +```dart +var buffer = StringBuffer() + ..write('one') + ..write('two') + ..write('three'); +``` -* `file-system.g.dart` -* `SliderMenu.css.dart` -The lint `library_names` can be used to enforce the same kind of naming on the -library. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1068.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1068.md index 2ff7623d..fd6f66a1 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1068.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1068.md @@ -1,41 +1,38 @@ --- -title: "Avoid using `as`." -verbose_name: "avoid_as" +title: "Avoid setters without getters" +verbose_name: "avoid_setters_without_getters" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using `as`. +**DON'T** define a setter without a corresponding getter. -If you know the type is correct, use an assertion or assign to a more -narrowly-typed variable (this avoids the type check in release mode; `as` is not -compiled out in release mode). If you don't know whether the type is -correct, check using `is` (this avoids the exception that `as` raises). +Defining a setter without defining a corresponding getter can lead to logical +inconsistencies. Doing this could allow you to set a property to some value, +but then upon observing the property's value, it could easily be different. **BAD:** ```dart -(pm as Person).firstName = 'Seth'; +class Bad { + int l, r; + + set length(int newLength) { + r = l + newLength; + } +} ``` **GOOD:** ```dart -if (pm is Person) - pm.firstName = 'Seth'; -``` +class Good { + int l, r; -but certainly not + int get length => r - l; -**BAD:** -```dart -try { - (pm as Person).firstName = 'Seth'; -} on CastError { } + set length(int newLength) { + r = l + newLength; + } +} ``` -Note that an exception is made in the case of `dynamic` since the cast has no -performance impact. -**OK:** -```dart -HasScrollDirection scrollable = renderObject as dynamic; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1069.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1069.md index 4bbb0985..5d02f1fc 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1069.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1069.md @@ -1,54 +1,24 @@ --- -title: "Don't use explicit `break`s when a break is implied." -verbose_name: "unnecessary_breaks" +title: "Avoid shadowing type parameters" +verbose_name: "avoid_shadowing_type_parameters" category: "antipattern" weight: 70 severity: "major" --- -Only use a `break` in a non-empty switch case statement if you need to break -before the end of the case body. Dart does not support fallthrough execution -for non-empty cases, so `break`s at the end of non-empty switch case statements -are unnecessary. +**AVOID** shadowing type parameters. **BAD:** ```dart -switch (1) { - case 1: - print("one"); - break; - case 2: - print("two"); - break; +class A { + void fn() {} } ``` **GOOD:** ```dart -switch (1) { - case 1: - print("one"); - case 2: - print("two"); +class A { + void fn() {} } ``` -```dart -switch (1) { - case 1: - case 2: - print("one or two"); -} -``` - -```dart -switch (1) { - case 1: - break; - case 2: - print("just two"); -} -``` -NOTE: This lint only reports unnecessary breaks in libraries with a -[language version](https://dart.dev/guides/language/evolution#language-versioning) -of 3.0 or greater. Explicit breaks are still required in Dart 2.19 and below. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1070.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1070.md index ce4faf7f..34aba069 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1070.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1070.md @@ -1,40 +1,20 @@ --- -title: "Type annotate public APIs." -verbose_name: "type_annotate_public_apis" +title: "Avoid single cascade in expression statements" +verbose_name: "avoid_single_cascade_in_expression_statements" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/design#do-type-annotate-fields-and-top-level-variables-if-the-type-isnt-obvious): - -**PREFER** type annotating public APIs. - -Type annotations are important documentation for how a library should be used. -Annotating the parameter and return types of public methods and functions helps -users understand what the API expects and what it provides. - -Note that if a public API accepts a range of values that Dart's type system -cannot express, then it is acceptable to leave that untyped. In that case, the -implicit `dynamic` is the correct type for the API. - -For code internal to a library (either private, or things like nested functions) -annotate where you feel it helps, but don't feel that you *must* provide them. +**AVOID** single cascade in expression statements. **BAD:** ```dart -install(id, destination) { - // ... -} +o..m(); ``` -Here, it's unclear what `id` is. A string? And what is `destination`? A string -or a `File` object? Is this method synchronous or asynchronous? - **GOOD:** ```dart -Future install(PackageId id, String destination) { - // ... -} +o.m(); ``` -With types, all of this is clarified. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1071.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1071.md index 2b063514..c35f2656 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1071.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1071.md @@ -1,51 +1,24 @@ --- -title: "Use matching super parameter names." -verbose_name: "matching_super_parameters" +title: "Avoid annotating types for function expression parameters" +verbose_name: "avoid_types_on_closure_parameters" category: "antipattern" weight: 70 severity: "major" --- -**DO** use super parameter names that match their corresponding super -constructor's parameter names. +**AVOID** annotating types for function expression parameters. -**BAD:** +Annotating types for function expression parameters is usually unnecessary +because the parameter types can almost always be inferred from the context, +thus making the practice redundant. +**BAD:** ```dart -class Rectangle { - final int width; - final int height; - - Rectangle(this.width, this.height); -} - -class ColoredRectangle extends Rectangle { - final Color color; - - ColoredRectangle( - this.color, - super.height, // Bad, actually corresponds to the `width` parameter. - super.width, // Bad, actually corresponds to the `height` parameter. - ); -} +var names = people.map((Person person) => person.name); ``` **GOOD:** - ```dart -class Rectangle { - final int width; - final int height; - - Rectangle(this.width, this.height); -} - -class ColoredRectangle extends Rectangle { - final Color color; - - ColoredRectangle( - this.color, - super.width, - super.height, - ); -} +var names = people.map((person) => person.name); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1072.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1072.md index 1077f30a..6f0af94c 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1072.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1072.md @@ -1,33 +1,42 @@ --- -title: "Don't check for null in custom == operators." -verbose_name: "avoid_null_checks_in_equality_operators" +title: "Avoid unnecessary containers" +verbose_name: "avoid_unnecessary_containers" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** check for null in custom == operators. +**AVOID** wrapping widgets in unnecessary containers. -As null is a special value, no instance of any class (other than `Null`) can be -equivalent to it. Thus, it is redundant to check whether the other instance is -null. +Wrapping a widget in `Container` with no other parameters set has no effect +and makes code needlessly more complex. **BAD:** ```dart -class Person { - final String? name; - - @override - operator ==(Object? other) => - other != null && other is Person && name == other.name; +Widget buildRow() { + return Container( + child: Row( + children: [ + const MyLogo(), + const Expanded( + child: Text('...'), + ), + ], + ) + ); } ``` **GOOD:** ```dart -class Person { - final String? name; - - @override - operator ==(Object? other) => other is Person && name == other.name; +Widget buildRow() { + return Row( + children: [ + const MyLogo(), + const Expanded( + child: Text('...'), + ), + ], + ); } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1073.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1073.md index 58f9249e..647b065b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1073.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1073.md @@ -1,35 +1,25 @@ --- -title: "Don't rename parameters of overridden methods." -verbose_name: "avoid_renaming_method_parameters" +title: "Avoid defining unused parameters in constructors" +verbose_name: "avoid_unused_constructor_parameters" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** rename parameters of overridden methods. - -Methods that override another method, but do not have their own documentation -comment, will inherit the overridden method's comment when `dart doc` produces -documentation. If the inherited method contains the name of the parameter (in -square brackets), then `dart doc` cannot link it correctly. +**AVOID** defining unused parameters in constructors. **BAD:** ```dart -abstract class A { - m(a); +class BadOne { + BadOne(int unusedParameter, [String unusedPositional]); } -abstract class B extends A { - m(b); +class BadTwo { + int c; + + BadTwo(int a, int b, int x) { + c = a + b; + } } ``` -**GOOD:** -```dart -abstract class A { - m(a); -} -abstract class B extends A { - m(a); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1074.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1074.md index f1797879..f637f9d9 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1074.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1074.md @@ -1,19 +1,38 @@ --- -title: "Prefer if elements to conditional expressions where possible." -verbose_name: "prefer_if_elements_to_conditional_expressions" +title: "Avoid async functions that return void" +verbose_name: "avoid_void_async" category: "antipattern" weight: 70 severity: "major" --- -When building collections, it is preferable to use `if` elements rather than -conditionals. +**DO** mark async functions as returning Future. + +When declaring an async method or function which does not return a value, +declare that it returns `Future` and not just `void`. **BAD:** ```dart -var list = ['a', 'b', condition ? 'c' : null].where((e) => e != null).toList(); +void f() async {} +void f2() async => null; ``` **GOOD:** ```dart -var list = ['a', 'b', if (condition) 'c']; +Future f() async {} +Future f2() async => null; ``` + +**EXCEPTION:** + +An exception is made for top-level `main` functions, where the `Future` +annotation *can* (and generally should) be dropped in favor of `void`. + +**GOOD:** +```dart +Future f() async {} + +void main() async { + await f(); +} +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1075.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1075.md index dc76275c..df0664bd 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1075.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1075.md @@ -1,29 +1,29 @@ --- -title: "Don't explicitly catch Error or types that implement it." -verbose_name: "avoid_catching_errors" +title: "Await only futures" +verbose_name: "await_only_futures" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** explicitly catch Error or types that implement it. +**AVOID** using await on anything which is not a future. -Errors differ from Exceptions in that Errors can be analyzed and prevented prior -to runtime. It should almost never be necessary to catch an error at runtime. +Await is allowed on the types: `Future`, `FutureOr`, `Future?`, +`FutureOr?` and `dynamic`. + +Further, using `await null` is specifically allowed as a way to introduce a +microtask delay. **BAD:** ```dart -try { - somethingRisky(); -} on Error catch(e) { - doSomething(e); +main() async { + print(await 23); } ``` - **GOOD:** ```dart -try { - somethingRisky(); -} on Exception catch(e) { - doSomething(e); +main() async { + await null; // If a delay is really intended. + print(23); } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1076.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1076.md index 3b1b6da0..008f44ef 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1076.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1076.md @@ -1,37 +1,25 @@ --- -title: "Don't use wildcard parameters or variables." -verbose_name: "no_wildcard_variable_uses" -category: "bug-risk" +title: "Name extensions using UpperCamelCase" +verbose_name: "camel_case_extensions" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use wildcard parameters or variables. +From [Effective Dart](https://dart.dev/effective-dart/style#do-name-extensions-using-uppercamelcase): -Wildcard parameters and local variables -(e.g. underscore-only names like `_`, `__`, `___`, etc.) will -become non-binding in a future version of the Dart language. -Any existing code that uses wildcard parameters or variables will -break. In anticipation of this change, and to make adoption easier, -this lint disallows wildcard and variable parameter uses. +**DO** name extensions using `UpperCamelCase`. +Extensions should capitalize the first letter of each word (including +the first word), and use no separators. -**BAD:** -```dart -var _ = 1; -print(_); // LINT -``` - +**GOOD:** ```dart -void f(int __) { - print(__); // LINT multiple underscores too +extension MyFancyList on List { + // ... } -``` -**GOOD:** -```dart -for (var _ in [1, 2, 3]) count++; +extension SmartIterable on Iterable { + // ... +} ``` -```dart -var [a, _, b, _] = [1, 2, 3, 4]; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1077.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1077.md index 012903f2..860837f6 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1077.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1077.md @@ -1,72 +1,28 @@ --- -title: "Do not pass `null` as an argument where a closure is expected." -verbose_name: "null_closures" +title: "Name types using UpperCamelCase" +verbose_name: "camel_case_types" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** pass `null` as an argument where a closure is expected. +From [Effective Dart](https://dart.dev/effective-dart/style#do-name-types-using-uppercamelcase): -Often a closure that is passed to a method will only be called conditionally, -so that tests and "happy path" production calls do not reveal that `null` will -result in an exception being thrown. +**DO** name types using UpperCamelCase. -This rule only catches null literals being passed where closures are expected -in the following locations: +Classes and typedefs should capitalize the first letter of each word (including +the first word), and use no separators. -#### Constructors - -* From `dart:async` - * `Future` at the 0th positional parameter - * `Future.microtask` at the 0th positional parameter - * `Future.sync` at the 0th positional parameter - * `Timer` at the 0th positional parameter - * `Timer.periodic` at the 1st positional parameter -* From `dart:core` - * `List.generate` at the 1st positional parameter - -#### Static functions - -* From `dart:async` - * `scheduleMicrotask` at the 0th positional parameter - * `Future.doWhile` at the 0th positional parameter - * `Future.forEach` at the 0th positional parameter - * `Future.wait` at the named parameter `cleanup` - * `Timer.run` at the 0th positional parameter - -#### Instance methods +**GOOD:** +```dart +class SliderMenu { + // ... +} -* From `dart:async` - * `Future.then` at the 0th positional parameter - * `Future.complete` at the 0th positional parameter -* From `dart:collection` - * `Queue.removeWhere` at the 0th positional parameter - * `Queue.retain - * `Iterable.firstWhere` at the 0th positional parameter, and the named - parameter `orElse` - * `Iterable.forEach` at the 0th positional parameter - * `Iterable.fold` at the 1st positional parameter - * `Iterable.lastWhere` at the 0th positional parameter, and the named - parameter `orElse` - * `Iterable.map` at the 0th positional parameter - * `Iterable.reduce` at the 0th positional parameter - * `Iterable.singleWhere` at the 0th positional parameter, and the named - parameter `orElse` - * `Iterable.skipWhile` at the 0th positional parameter - * `Iterable.takeWhile` at the 0th positional parameter - * `Iterable.where` at the 0th positional parameter - * `List.removeWhere` at the 0th positional parameter - * `List.retainWhere` at the 0th positional parameter - * `String.replaceAllMapped` at the 1st positional parameter - * `String.replaceFirstMapped` at the 1st positional parameter - * `String.splitMapJoin` at the named parameters `onMatch` and `onNonMatch` +class HttpRequest { + // ... +} -**BAD:** -```dart -[1, 3, 5].firstWhere((e) => e.isOdd, orElse: null); +typedef num Adder(num x, num y); ``` -**GOOD:** -```dart -[1, 3, 5].firstWhere((e) => e.isOdd, orElse: () => null); -``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1078.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1078.md index 5314fff1..71711298 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1078.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1078.md @@ -1,44 +1,45 @@ --- -title: "Prefer const with constant constructors." -verbose_name: "prefer_const_constructors" +title: "Cascade consecutive method invocations on the same reference" +verbose_name: "cascade_invocations" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** using `const` for instantiating constant constructors. - -If a constructor can be invoked as const to produce a canonicalized instance, -it's preferable to do so. +**DO** Use the cascading style when successively invoking methods on the same +reference. **BAD:** ```dart -class A { - const A(); -} +SomeClass someReference = SomeClass(); +someReference.firstMethod(); +someReference.secondMethod(); +``` -void accessA() { - A a = new A(); -} +**BAD:** +```dart +SomeClass someReference = SomeClass(); +... +someReference.firstMethod(); +someReference.aProperty = value; +someReference.secondMethod(); ``` **GOOD:** ```dart -class A { - const A(); -} - -void accessA() { - A a = const A(); -} +SomeClass someReference = SomeClass() + ..firstMethod() + ..aProperty = value + ..secondMethod(); ``` **GOOD:** ```dart -class A { - final int x; +SomeClass someReference = SomeClass(); +... +someReference + ..firstMethod() + ..aProperty = value + ..secondMethod(); +``` - const A(this.x); -} -A foo(int x) => new A(x); -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1079.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1079.md index 78c7326d..19423af3 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1079.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1079.md @@ -1,85 +1,31 @@ --- -title: "Conditions should not unconditionally evaluate to `true` or to `false`." -verbose_name: "invariant_booleans" -category: "bug-risk" +title: "Don't cast a nullable value to a non nullable type" +verbose_name: "cast_nullable_to_non_nullable" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** test for conditions that can be inferred at compile time or test the -same condition twice. - -Conditional statements using a condition which cannot be anything but `false` -have the effect of making blocks of code non-functional. If the condition -cannot evaluate to anything but `true`, the conditional statement is completely -redundant, and makes the code less readable. -It is quite likely that the code does not match the programmer's intent. -Either the condition should be removed or it should be updated so that it does -not always evaluate to `true` or `false` and does not perform redundant tests. -This rule will hint to the test conflicting with the linted one. - -**BAD:** -```dart -// foo can't be both equal and not equal to bar in the same expression -if(foo == bar && something && foo != bar) {...} -``` +**DON'T** cast a nullable value to a non nullable type. This hides a null check +and most of the time it is not what is expected. **BAD:** ```dart -void compute(int foo) { - if (foo == 4) { - doSomething(); - // we know foo is equal to 4 at this point, so the next condition is always false - if (foo > 4) {...} - ... - } - ... -} -``` +class A {} +class B extends A {} -**BAD:** -```dart -void compute(bool foo) { - if (foo) { - return; - } - doSomething(); - // foo is always false here - if (foo){...} - ... -} +A? a; +var v = a as B; +var v = a as A; ``` **GOOD:** ```dart -void nestedOK() { - if (foo == bar) { - foo = baz; - if (foo != bar) {...} - } -} -``` - -**GOOD:** -```dart -void nestedOk2() { - if (foo == bar) { - return; - } +class A {} +class B extends A {} - foo = baz; - if (foo == bar) {...} // OK -} +A? a; +var v = a! as B; +var v = a!; ``` -**GOOD:** -```dart -void nestedOk5() { - if (foo != null) { - if (bar != null) { - return; - } - } - if (bar != null) {...} // OK -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1080.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1080.md index e87df790..6cb645a3 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1080.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1080.md @@ -1,21 +1,22 @@ --- -title: "Avoid using braces in interpolation when not needed." -verbose_name: "unnecessary_brace_in_string_interps" +title: "Sort combinator names alphabetically" +verbose_name: "combinators_ordering" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using braces in interpolation when not needed. - -If you're just interpolating a simple identifier, and it's not immediately -followed by more alphanumeric text, the `{}` can and should be omitted. +**DO** sort combinator names alphabetically. **BAD:** ```dart -print("Hi, ${name}!"); +import 'a.dart' show B, A hide D, C; +export 'a.dart' show B, A hide D, C; ``` **GOOD:** ```dart -print("Hi, $name!"); +import 'a.dart' show A, B hide C, D; +export 'a.dart' show A, B hide C, D; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1081.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1081.md index d124a935..a0ed9eaa 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1081.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1081.md @@ -1,22 +1,25 @@ --- -title: "Avoid shadowing type parameters." -verbose_name: "avoid_shadowing_type_parameters" +title: "Missing conditional import" +verbose_name: "conditional_uri_does_not_exist" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** shadowing type parameters. +**DON'T** reference files that do not exist in conditional imports. + +Code may fail at runtime if the condition evaluates such that the missing file +needs to be imported. **BAD:** ```dart -class A { - void fn() {} -} +import 'file_that_does_exist.dart' + if (condition) 'file_that_does_not_exist.dart'; ``` **GOOD:** ```dart -class A { - void fn() {} -} +import 'file_that_does_exist.dart' + if (condition) 'file_that_also_does_exist.dart'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1082.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1082.md index 615000dd..55eeb7e7 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1082.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1082.md @@ -1,31 +1,37 @@ --- -title: "Use rethrow to rethrow a caught exception." -verbose_name: "use_rethrow_when_possible" +title: "Prefer using lowerCamelCase for constant names" +verbose_name: "constant_identifier_names" category: "antipattern" weight: 70 severity: "major" --- -**DO** use rethrow to rethrow a caught exception. +**PREFER** using lowerCamelCase for constant names. -As Dart provides rethrow as a feature, it should be used to improve terseness -and readability. +In new code, use `lowerCamelCase` for constant variables, including enum values. + +In existing code that uses `ALL_CAPS_WITH_UNDERSCORES` for constants, you may +continue to use all caps to stay consistent. **BAD:** ```dart -try { - somethingRisky(); -} catch(e) { - if (!canHandle(e)) throw e; - handle(e); +const PI = 3.14; +const kDefaultTimeout = 1000; +final URL_SCHEME = RegExp('^([a-z]+):'); + +class Dice { + static final NUMBER_GENERATOR = Random(); } ``` **GOOD:** ```dart -try { - somethingRisky(); -} catch(e) { - if (!canHandle(e)) rethrow; - handle(e); +const pi = 3.14; +const defaultTimeout = 1000; +final urlScheme = RegExp('^([a-z]+):'); + +class Dice { + static final numberGenerator = Random(); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1083.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1083.md index 7a2b11d6..5fee7a97 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1083.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1083.md @@ -1,57 +1,46 @@ --- -title: "Invocation of various collection methods with arguments of unrelated types." -verbose_name: "collection_methods_unrelated_type" -category: "bug-risk" +title: "DO use curly braces for all flow control structures" +verbose_name: "curly_braces_in_flow_control_structures" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** invoke certain collection method with an argument with an unrelated -type. +**DO** use curly braces for all flow control structures. -Doing this will invoke `==` on the collection's elements and most likely will -return `false`. - -An argument passed to a collection method should relate to the collection type -as follows: - -* an argument to `Iterable.contains` should be related to `E` -* an argument to `List.remove` should be related to `E` -* an argument to `Map.containsKey` should be related to `K` -* an argument to `Map.containsValue` should be related to `V` -* an argument to `Map.remove` should be related to `K` -* an argument to `Map.[]` should be related to `K` -* an argument to `Queue.remove` should be related to `E` -* an argument to `Set.lookup` should be related to `E` -* an argument to `Set.remove` should be related to `E` +Doing so avoids the [dangling else](https://en.wikipedia.org/wiki/Dangling_else) +problem. **BAD:** ```dart -void someFunction() { - var list = []; - if (list.contains('1')) print('someFunction'); // LINT -} +if (overflowChars != other.overflowChars) + return overflowChars < other.overflowChars; ``` -**BAD:** +**GOOD:** ```dart -void someFunction() { - var set = {}; - set.remove('1'); // LINT +if (isWeekDay) { + print('Bike to work!'); +} else { + print('Go dancing or read a book!'); } ``` +There is one exception to this: an `if` statement with no `else` clause where +the entire `if` statement and the then body all fit in one line. In that case, +you may leave off the braces if you prefer: + **GOOD:** ```dart -void someFunction() { - var list = []; - if (list.contains(1)) print('someFunction'); // OK -} +if (arg == null) return defaultValue; ``` +If the body wraps to the next line, though, use braces: + **GOOD:** ```dart -void someFunction() { - var set = {}; - set.remove(1); // OK +if (overflowChars != other.overflowChars) { + return overflowChars < other.overflowChars; } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1084.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1084.md index eeacda66..85192303 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1084.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1084.md @@ -1,36 +1,36 @@ --- -title: "Place the `super` call last in a constructor initialization list." -verbose_name: "super_goes_last" +title: "Attach library doc comments to library directives" +verbose_name: "dangling_library_doc_comments" category: "antipattern" weight: 70 severity: "major" --- -**DO** place the `super` call last in a constructor initialization list. - -Field initializers are evaluated in the order that they appear in the -constructor initialization list. If you place a `super()` call in the middle of -an initializer list, the superclass's initializers will be evaluated right then -before evaluating the rest of the subclass's initializers. - -What it doesn't mean is that the superclass's constructor body will be executed -then. That always happens after all initializers are run regardless of where -`super` appears. It's vanishingly rare that the order of initializers matters, -so the placement of `super` in the list almost never matters either. - -Getting in the habit of placing it last improves consistency, visually -reinforces when the superclass's constructor body is run, and may help -performance. +Attach library doc comments (with `///`) to library directives, rather than +leaving them dangling near the top of a library. **BAD:** ```dart -View(Style style, List children) - : super(style), - _children = children { +/// This is a great library. +import 'package:math'; +``` + +```dart +/// This is a great library. + +class C {} ``` **GOOD:** ```dart -View(Style style, List children) - : _children = children, - super(style) { +/// This is a great library. +library; + +import 'package:math'; + +class C {} ``` + +**NOTE:** An unnamed library, like `library;` above, is only supported in Dart +2.19 and later. Code which might run in earlier versions of Dart will need to +provide a name in the `library` directive. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1085.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1085.md index 694de1ac..8ca71e6c 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1085.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1085.md @@ -1,27 +1,48 @@ --- -title: "Prefer using a boolean as the assert condition." -verbose_name: "prefer_bool_in_asserts" +title: "Missing deprecated annotation" +verbose_name: "deprecated_consistency" category: "antipattern" weight: 70 severity: "major" --- -**DO** use a boolean for assert conditions. +**DO** apply `@Deprecated()` consistently: -Not using booleans in assert conditions can lead to code where it isn't clear -what the intention of the assert statement is. +- if a class is deprecated, its constructors should also be deprecated. +- if a field is deprecated, the constructor parameter pointing to it should also + be deprecated. +- if a constructor parameter pointing to a field is deprecated, the field should + also be deprecated. **BAD:** ```dart -assert(() { - f(); - return true; -}); +@deprecated +class A { + A(); +} + +class B { + B({this.field}); + @deprecated + Object field; +} ``` **GOOD:** ```dart -assert(() { - f(); - return true; -}()); +@deprecated +class A { + @deprecated + A(); +} + +class B { + B({@deprecated this.field}); + @deprecated + Object field; +} + +class C extends B { + C({@deprecated super.field}); +} ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1086.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1086.md index 9760f4b7..1fc6cdba 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1086.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1086.md @@ -1,28 +1,105 @@ --- -title: "Avoid using `forEach` with a function literal." -verbose_name: "avoid_function_literals_in_foreach_calls" +title: "Adhere to Effective Dart Guide directives sorting conventions" +verbose_name: "directives_ordering" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using `forEach` with a function literal. +**DO** follow the directive ordering conventions in +[Effective Dart](https://dart.dev/effective-dart/style#ordering): -The `for` loop enables a developer to be clear and explicit as to their intent. -A return in the body of the `for` loop returns from the body of the function, -where as a return in the body of the `forEach` closure only returns a value -for that iteration of the `forEach`. The body of a `for` loop can contain -`await`s, while the closure body of a `forEach` cannot. +**DO** place `dart:` imports before other imports. **BAD:** ```dart -people.forEach((person) { - ... -}); +import 'package:bar/bar.dart'; +import 'package:foo/foo.dart'; + +import 'dart:async'; // LINT +import 'dart:html'; // LINT +``` + +**BAD:** +```dart +import 'dart:html'; // OK +import 'package:bar/bar.dart'; + +import 'dart:async'; // LINT +import 'package:foo/foo.dart'; ``` **GOOD:** ```dart -for (var person in people) { - ... -} +import 'dart:async'; // OK +import 'dart:html'; // OK + +import 'package:bar/bar.dart'; +import 'package:foo/foo.dart'; +``` + +**DO** place `package:` imports before relative imports. + +**BAD:** +```dart +import 'a.dart'; +import 'b.dart'; + +import 'package:bar/bar.dart'; // LINT +import 'package:foo/foo.dart'; // LINT +``` + +**BAD:** +```dart +import 'package:bar/bar.dart'; // OK +import 'a.dart'; + +import 'package:foo/foo.dart'; // LINT +import 'b.dart'; +``` + +**GOOD:** +```dart +import 'package:bar/bar.dart'; // OK +import 'package:foo/foo.dart'; // OK + +import 'a.dart'; +import 'b.dart'; ``` + +**DO** specify exports in a separate section after all imports. + +**BAD:** +```dart +import 'src/error.dart'; +export 'src/error.dart'; // LINT +import 'src/string_source.dart'; +``` + +**GOOD:** +```dart +import 'src/error.dart'; +import 'src/string_source.dart'; + +export 'src/error.dart'; // OK +``` + +**DO** sort sections alphabetically. + +**BAD:** +```dart +import 'package:foo/bar.dart'; // OK +import 'package:bar/bar.dart'; // LINT + +import 'a/b.dart'; // OK +import 'a.dart'; // LINT +``` + +**GOOD:** +```dart +import 'package:bar/bar.dart'; // OK +import 'package:foo/bar.dart'; // OK + +import 'a.dart'; // OK +import 'a/b.dart'; // OK +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1087.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1087.md index 3767ae87..cb5f97d1 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1087.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1087.md @@ -1,28 +1,18 @@ --- -title: "Unnecessary await keyword in return." -verbose_name: "unnecessary_await_in_return" +title: "Do not use environment declared variables" +verbose_name: "do_not_use_environment" category: "antipattern" weight: 70 severity: "major" --- -Avoid returning an awaited expression when the expression type is assignable to -the function's return type. +Using values derived from the environment at compile-time, creates +hidden global state and makes applications hard to understand and maintain. +**DON'T** use `fromEnvironment` or `hasEnvironment` factory constructors. **BAD:** ```dart -Future future; -Future f1() async => await future; -Future f2() async { - return await future; -} +const loggingLevel = + bool.hasEnvironment('logging') ? String.fromEnvironment('logging') : null; ``` -**GOOD:** -```dart -Future future; -Future f1() => future; -Future f2() { - return future; -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1088.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1088.md index dd020f2e..5555b274 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1088.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1088.md @@ -1,27 +1,43 @@ --- -title: "Unnecessary null checks." -verbose_name: "unnecessary_null_checks" +title: "Avoid empty catch blocks" +verbose_name: "empty_catches" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** apply a null check when a nullable value is accepted. +**AVOID** empty catch blocks. + +In general, empty catch blocks should be avoided. In cases where they are +intended, a comment should be provided to explain why exceptions are being +caught and suppressed. Alternatively, the exception identifier can be named with +underscores (e.g., `_`) to indicate that we intend to skip it. **BAD:** ```dart -f(int? i) {} -m() { - int? j; - f(j!); -} - +try { + ... +} catch(exception) { } ``` **GOOD:** ```dart -f(int? i) {} -m() { - int? j; - f(j); +try { + ... +} catch(e) { + // ignored, really. +} + +// Alternatively: +try { + ... +} catch(_) { } + +// Better still: +try { + ... +} catch(e) { + doSomething(e); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1089.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1089.md index c896f619..8fc40421 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1089.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1089.md @@ -1,49 +1,32 @@ --- -title: "Avoid `print` calls in production code." -verbose_name: "avoid_print" -category: "bug-risk" +title: "Use `;` instead of `{}` for empty constructor bodies" +verbose_name: "empty_constructor_bodies" +category: "antipattern" weight: 70 severity: "major" --- -**DO** avoid `print` calls in production code. +From [Effective Dart](https://dart.dev/effective-dart/usage#do-use--instead-of--for-empty-constructor-bodies): -For production code, consider using a logging framework. -If you are using Flutter, you can use `debugPrint` -or surround `print` calls with a check for `kDebugMode` - -**BAD:** -```dart -void f(int x) { - print('debug: $x'); - ... -} -``` +**DO** use `;` instead of `{}` for empty constructor bodies. +In Dart, a constructor with an empty body can be terminated with just a +semicolon. This is required for const constructors. For consistency and +brevity, other constructors should also do this. -**GOOD:** +**BAD:** ```dart -void f(int x) { - debugPrint('debug: $x'); - ... +class Point { + int x, y; + Point(this.x, this.y) {} } ``` - **GOOD:** ```dart -void f(int x) { - log('log: $x'); - ... +class Point { + int x, y; + Point(this.x, this.y); } ``` -**GOOD:** -```dart -void f(int x) { - if (kDebugMode) { - print('debug: $x'); - } - ... -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1090.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1090.md index 3601a574..8afcb3c9 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1090.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1090.md @@ -1,18 +1,22 @@ --- -title: "Prefer to use whereType on iterable." -verbose_name: "prefer_iterable_whereType" +title: "Put a single newline at end of file" +verbose_name: "eol_at_end_of_file" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** `iterable.whereType()` over `iterable.where((e) => e is T)`. +**DO** put a single newline at the end of non-empty files. **BAD:** ```dart -iterable.where((e) => e is MyClass); +a { +} ``` **GOOD:** ```dart -iterable.whereType(); +b { +} + <-- newline ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1091.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1091.md index 89c810f8..eeccbee7 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1091.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1091.md @@ -1,38 +1,67 @@ --- -title: "Prefer final for variable declarations if they are not reassigned." -verbose_name: "prefer_final_locals" +title: "Define case clauses for all constants in enum-like classes" +verbose_name: "exhaustive_cases" category: "antipattern" weight: 70 severity: "major" --- -**DO** prefer declaring variables as final if they are not reassigned later in -the code. +Switching on instances of enum-like classes should be exhaustive. -Declaring variables as final when possible is a good practice because it helps -avoid accidental reassignments and allows the compiler to do optimizations. +Enum-like classes are defined as concrete (non-abstract) classes that have: + * only private non-factory constructors + * two or more static const fields whose type is the enclosing class and + * no subclasses of the class in the defining library + +**DO** define case clauses for all constants in enum-like classes. **BAD:** ```dart -void badMethod() { - var label = 'hola mundo! badMethod'; // LINT - print(label); +class EnumLike { + final int i; + const EnumLike._(this.i); + + static const e = EnumLike._(1); + static const f = EnumLike._(2); + static const g = EnumLike._(3); } -``` -**GOOD:** -```dart -void goodMethod() { - final label = 'hola mundo! goodMethod'; - print(label); +void bad(EnumLike e) { + // Missing case. + switch(e) { // LINT + case EnumLike.e : + print('e'); + break; + case EnumLike.f : + print('f'); + break; + } } ``` **GOOD:** ```dart -void mutableCase() { - var label = 'hola mundo! mutableCase'; - print(label); - label = 'hello world'; - print(label); +class EnumLike { + final int i; + const EnumLike._(this.i); + + static const e = EnumLike._(1); + static const f = EnumLike._(2); + static const g = EnumLike._(3); +} + +void ok(EnumLike e) { + // All cases covered. + switch(e) { // OK + case EnumLike.e : + print('e'); + break; + case EnumLike.f : + print('f'); + break; + case EnumLike.g : + print('g'); + break; + } } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1092.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1092.md index 96642037..a348b8ac 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1092.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1092.md @@ -1,43 +1,37 @@ --- -title: "Use throwsA matcher instead of fail()." -verbose_name: "use_test_throws_matchers" +title: "Name source files using `lowercase_with_underscores`" +verbose_name: "file_names" category: "antipattern" weight: 70 severity: "major" --- -Use the `throwsA` matcher instead of try-catch with `fail()`. +**DO** name source files using `lowercase_with_underscores`. + +Some file systems are not case-sensitive, so many projects require filenames to +be all lowercase. Using a separating character allows names to still be readable +in that form. Using underscores as the separator ensures that the name is still +a valid Dart identifier, which may be helpful if the language later supports +symbolic imports. **BAD:** -```dart -// sync code -try { - someSyncFunctionThatThrows(); - fail('expected Error'); -} on Error catch (error) { - expect(error.message, contains('some message')); -} - -// async code -try { - await someAsyncFunctionThatThrows(); - fail('expected Error'); -} on Error catch (error) { - expect(error.message, contains('some message')); -} -``` +* `SliderMenu.dart` +* `filesystem.dart` +* `file-system.dart` **GOOD:** -```dart -// sync code -expect( - () => someSyncFunctionThatThrows(), - throwsA(isA().having((Error error) => error.message, 'message', contains('some message'))), -); - -// async code -await expectLater( - () => someAsyncFunctionThatThrows(), - throwsA(isA().having((Error error) => error.message, 'message', contains('some message'))), -); -``` + +* `slider_menu.dart` +* `file_system.dart` + +Files without a strict `.dart` extension are ignored. For example: + +**OK:** + +* `file-system.g.dart` +* `SliderMenu.css.dart` + +The lint `library_names` can be used to enforce the same kind of naming on the +library. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1093.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1093.md index e9278ea0..2f52e4cb 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1093.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1093.md @@ -1,36 +1,20 @@ --- -title: "Don't specify the `late` modifier when it is not needed." -verbose_name: "unnecessary_late" +title: "Use Flutter TODO format: // TODO(username): message, https://URL-to-issue" +verbose_name: "flutter_style_todos" category: "antipattern" weight: 70 severity: "major" --- -**DO** not specify the `late` modifier for top-level and static variables -when the declaration contains an initializer. +**DO** use Flutter TODO format. -Top-level and static variables with initializers are already evaluated lazily -as if they are marked `late`. +From the [Flutter docs](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#comments): -**BAD:** -```dart -late String badTopLevel = ''; -``` +> TODOs should include the string TODO in all caps, followed by the GitHub username of the person with the best context about the problem referenced by the TODO in parenthesis. A TODO is not a commitment that the person referenced will fix the problem, it is intended to be the person with enough context to explain the problem. Thus, when you create a TODO, it is almost always your username that is given. **GOOD:** ```dart -String goodTopLevel = ''; +// TODO(username): message. +// TODO(username): message, https://URL-to-issue. ``` -**BAD:** -```dart -class BadExample { - static late String badStatic = ''; -} -``` -**GOOD:** -```dart -class GoodExample { - late String goodStatic; -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1094.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1094.md index 8b0eaef5..4cb6afa4 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1094.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1094.md @@ -1,37 +1,30 @@ --- -title: "Annotate overridden members." -verbose_name: "annotate_overrides" +title: "Don't import implementation files from another package" +verbose_name: "implementation_imports" category: "antipattern" weight: 70 severity: "major" --- -**DO** annotate overridden methods and fields. +From the the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files): -This practice improves code readability and helps protect against -unintentionally overriding superclass members. +**DON'T** import implementation files from another package. + +The libraries inside `lib` are publicly visible: other packages are free to +import them. But much of a package's code is internal implementation libraries +that should only be imported and used by the package itself. Those go inside a +subdirectory of `lib` called `src`. You can create subdirectories in there if +it helps you organize things. + +You are free to import libraries that live in `lib/src` from within other Dart +code in the same package (like other libraries in `lib`, scripts in `bin`, +and tests) but you should never import from another package's `lib/src` +directory. Those files are not part of the package's public API, and they +might change in ways that could break your code. **BAD:** ```dart -class Cat { - int get lives => 9; -} - -class Lucky extends Cat { - final int lives = 14; -} +// In 'road_runner' +import 'package:acme/src/internals.dart'; ``` -**GOOD:** -```dart -abstract class Dog { - String get breed; - void bark() {} -} -class Husky extends Dog { - @override - final String breed = 'Husky'; - @override - void bark() {} -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1095.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1095.md index bebb6900..d9f8da46 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1095.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1095.md @@ -1,23 +1,37 @@ --- -title: "Avoid null in null-aware assignment." -verbose_name: "unnecessary_null_aware_assignments" +title: "Explicitly tear-off `call` methods when using an object as a Function" +verbose_name: "implicit_call_tearoffs" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** `null` in null-aware assignment. - -Using `null` on the right-hand side of a null-aware assignment effectively makes -the assignment redundant. +**DO** +Explicitly tear off `.call` methods from objects when assigning to a Function +type. There is less magic with an explicit tear off. Future language versions +may remove the implicit call tear off. **BAD:** ```dart -var x; -x ??= null; +class Callable { + void call() {} +} +void callIt(void Function() f) { + f(); +} + +callIt(Callable()); ``` **GOOD:** ```dart -var x; -x ??= 1; +class Callable { + void call() {} +} +void callIt(void Function() f) { + f(); +} + +callIt(Callable().call); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1096.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1096.md index 86405e84..c423d3a1 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1096.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1096.md @@ -1,39 +1,29 @@ --- -title: "Avoid wrapping fields in getters and setters just to be \"safe\"." -verbose_name: "unnecessary_getters_setters" +title: "Join return statement with assignment when possible" +verbose_name: "join_return_with_assignment" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/usage#dont-wrap-a-field-in-a-getter-and-setter-unnecessarily): - -**AVOID** wrapping fields in getters and setters just to be "safe". - -In Java and C#, it's common to hide all fields behind getters and setters (or -properties in C#), even if the implementation just forwards to the field. That -way, if you ever need to do more work in those members, you can do it without needing -to touch the callsites. This is because calling a getter method is different -than accessing a field in Java, and accessing a property isn't binary-compatible -with accessing a raw field in C#. - -Dart doesn't have this limitation. Fields and getters/setters are completely -indistinguishable. You can expose a field in a class and later wrap it in a -getter and setter without having to touch any code that uses that field. +**DO** join return statement with assignment when possible. **BAD:** ```dart -class Box { - var _contents; - get contents => _contents; - set contents(value) { - _contents = value; +class A { + B _lazyInstance; + static B get instance { + _lazyInstance ??= B(); // LINT + return _lazyInstance; } } ``` **GOOD:** ```dart -class Box { - var contents; +class A { + B _lazyInstance; + static B get instance => _lazyInstance ??= B(); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1097.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1097.md index 9aaa420c..866c26d2 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1097.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1097.md @@ -1,27 +1,30 @@ --- -title: "Join return statement with assignment when possible." -verbose_name: "join_return_with_assignment" +title: "Start multiline strings with a newline" +verbose_name: "leading_newlines_in_multiline_strings" category: "antipattern" weight: 70 severity: "major" --- -**DO** join return statement with assignment when possible. +Multiline strings are easier to read when they start with a newline (a newline +starting a multiline string is ignored). **BAD:** ```dart -class A { - B _lazyInstance; - static B get instance { - _lazyInstance ??= B(); // LINT - return _lazyInstance; - } -} +var s1 = '''{ + "a": 1, + "b": 2 +}'''; ``` **GOOD:** ```dart -class A { - B _lazyInstance; - static B get instance => _lazyInstance ??= B(); -} +var s1 = ''' +{ + "a": 1, + "b": 2 +}'''; + +var s2 = '''This one-liner multiline string is ok. It usually allows to escape both ' and " in the string.'''; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1098.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1098.md index d4eec476..7cd46406 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1098.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1098.md @@ -1,28 +1,33 @@ --- -title: "Don't use adjacent strings in list." -verbose_name: "no_adjacent_strings_in_list" -category: "bug-risk" +title: "Attach library annotations to library directives" +verbose_name: "library_annotations" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use adjacent strings in a list. - -This can indicate a forgotten comma. +Attach library annotations to library directives, rather than +some other library-level element. **BAD:** ```dart -List list = [ - 'a' - 'b', - 'c', -]; +@TestOn('browser') + +import 'package:test/test.dart'; + +void main() {} ``` **GOOD:** ```dart -List list = [ - 'a' + - 'b', - 'c', -]; +@TestOn('browser') +library; + +import 'package:test/test.dart'; + +void main() {} ``` + +**NOTE:** An unnamed library, like `library;` above, is only supported in Dart +2.19 and later. Code which might run in earlier versions of Dart will need to +provide a name in the `library` directive. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1099.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1099.md index 641ac634..87dab144 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1099.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1099.md @@ -1,77 +1,29 @@ --- -title: "Avoid control flow in finally blocks." -verbose_name: "control_flow_in_finally" -category: "bug-risk" +title: "Name libraries using `lowercase_with_underscores`" +verbose_name: "library_names" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** control flow leaving finally blocks. +**DO** name libraries using `lowercase_with_underscores`. -Using control flow in finally blocks will inevitably cause unexpected behavior -that is hard to debug. +Some file systems are not case-sensitive, so many projects require filenames to +be all lowercase. Using a separating character allows names to still be readable +in that form. Using underscores as the separator ensures that the name is still +a valid Dart identifier, which may be helpful if the language later supports +symbolic imports. **BAD:** ```dart -class BadReturn { - double nonCompliantMethod() { - try { - return 1 / 0; - } catch (e) { - print(e); - } finally { - return 1.0; // LINT - } - } -} +library peg-parser; ``` -**BAD:** +**GOOD:** ```dart -class BadContinue { - double nonCompliantMethod() { - for (var o in [1, 2]) { - try { - print(o / 0); - } catch (e) { - print(e); - } finally { - continue; // LINT - } - } - return 1.0; - } -} +library peg_parser; ``` -**BAD:** -```dart -class BadBreak { - double nonCompliantMethod() { - for (var o in [1, 2]) { - try { - print(o / 0); - } catch (e) { - print(e); - } finally { - break; // LINT - } - } - return 1.0; - } -} -``` +The lint `file_names` can be used to enforce the same kind of naming on the +file. + -**GOOD:** -```dart -class Ok { - double compliantMethod() { - var i = 5; - try { - i = 1 / 0; - } catch (e) { - print(e); // OK - } - return i; - } -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1100.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1100.md index 8cfec1b0..9d784d52 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1100.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1100.md @@ -1,41 +1,26 @@ --- -title: "SizedBox for whitespace." -verbose_name: "sized_box_for_whitespace" +title: "Use `lowercase_with_underscores` when specifying a library prefix" +verbose_name: "library_prefixes" category: "antipattern" weight: 70 severity: "major" --- -Use SizedBox to add whitespace to a layout. - -A `Container` is a heavier Widget than a `SizedBox`, and as bonus, `SizedBox` -has a `const` constructor. +**DO** use `lowercase_with_underscores` when specifying a library prefix. **BAD:** ```dart -Widget buildRow() { - return Row( - children: [ - const MyLogo(), - Container(width: 4), - const Expanded( - child: Text('...'), - ), - ], - ); -} +import 'dart:math' as Math; +import 'dart:json' as JSON; +import 'package:js/js.dart' as JS; +import 'package:javascript_utils/javascript_utils.dart' as jsUtils; ``` **GOOD:** ```dart -Widget buildRow() { - return Row( - children: const [ - MyLogo(), - SizedBox(width: 4), - Expanded( - child: Text('...'), - ), - ], - ); -} +import 'dart:math' as math; +import 'dart:json' as json; +import 'package:js/js.dart' as js; +import 'package:javascript_utils/javascript_utils.dart' as js_utils; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1101.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1101.md index f1cf9db2..262a0df7 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1101.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1101.md @@ -1,52 +1,34 @@ --- -title: "Document all public members." -verbose_name: "public_member_api_docs" +title: "Avoid using private types in public APIs" +verbose_name: "library_private_types_in_public_api" category: "antipattern" weight: 70 severity: "major" --- -**DO** document all public members. +**AVOID** using library private types in public APIs. -All non-overriding public members should be documented with `///` doc-style -comments. +For the purposes of this lint, a public API is considered to be any top-level or +member declaration unless the declaration is library private or contained in a +declaration that's library private. The following uses of types are checked: + +- the return type of a function or method, +- the type of any parameter of a function or method, +- the bound of a type parameter to any function, method, class, mixin, + extension's extended type, or type alias, +- the type of any top level variable or field, +- any type used in the declaration of a type alias (for example + `typedef F = _Private Function();`), or +- any type used in the `on` clause of an extension or a mixin **BAD:** ```dart -class Bad { - void meh() { } -} +f(_Private p) { ... } +class _Private {} ``` **GOOD:** ```dart -/// A good thing. -abstract class Good { - /// Start doing your thing. - void start() => _start(); - - _start(); -} +f(String s) { ... } ``` -In case a public member overrides a member it is up to the declaring member -to provide documentation. For example, in the following, `Sub` needn't -document `init` (though it certainly may, if there's need). - -**GOOD:** -```dart -/// Base of all things. -abstract class Base { - /// Initialize the base. - void init(); -} - -/// A sub base. -class Sub extends Base { - @override - void init() { ... } -} -``` -Note that consistent with `dart doc`, an exception to the rule is made when -documented getters have corresponding undocumented setters. In this case the -setters inherit the docs from the getters. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1102.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1102.md index f07eb661..bbe3053c 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1102.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1102.md @@ -1,24 +1,28 @@ --- -title: "Use `lowercase_with_underscores` when specifying a library prefix." -verbose_name: "library_prefixes" +title: "Avoid lines longer than 80 characters" +verbose_name: "lines_longer_than_80_chars" category: "antipattern" weight: 70 severity: "major" --- -**DO** use `lowercase_with_underscores` when specifying a library prefix. +**AVOID** lines longer than 80 characters -**BAD:** -```dart -import 'dart:math' as Math; -import 'dart:json' as JSON; -import 'package:js/js.dart' as JS; -import 'package:javascript_utils/javascript_utils.dart' as jsUtils; -``` +Readability studies show that long lines of text are harder to read because your +eye has to travel farther when moving to the beginning of the next line. This is +why newspapers and magazines use multiple columns of text. + +If you really find yourself wanting lines longer than 80 characters, our +experience is that your code is likely too verbose and could be a little more +compact. The main offender is usually `VeryLongCamelCaseClassNames`. Ask +yourself, “Does each word in that type name tell me something critical or +prevent a name collision?” If not, consider omitting it. + +Note that `dart format` does 99% of this for you, but the last 1% is you. It +does not split long string literals to fit in 80 columns, so you have to do +that manually. + +We make an exception for URIs and file paths. When those occur in comments or +strings (usually in imports and exports), they may remain on a single line even +if they go over the line limit. This makes it easier to search source files for +a given path. -**GOOD:** -```dart -import 'dart:math' as math; -import 'dart:json' as json; -import 'package:js/js.dart' as js; -import 'package:javascript_utils/javascript_utils.dart' as js_utils; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1103.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1103.md index 053bfe48..a980f509 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1103.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1103.md @@ -1,11 +1,52 @@ --- -title: "Avoid returning null for Future." -verbose_name: "avoid_returning_null_for_future" -category: "bug-risk" +title: "Use matching super parameter names" +verbose_name: "matching_super_parameters" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** returning null for Future. +**DO** use super parameter names that match their corresponding super +constructor's parameter names. + +**BAD:** + +```dart +class Rectangle { + final int width; + final int height; + + Rectangle(this.width, this.height); +} + +class ColoredRectangle extends Rectangle { + final Color color; + + ColoredRectangle( + this.color, + super.height, // Bad, actually corresponds to the `width` parameter. + super.width, // Bad, actually corresponds to the `height` parameter. + ); +} +``` + +**GOOD:** + +```dart +class Rectangle { + final int width; + final int height; + + Rectangle(this.width, this.height); +} + +class ColoredRectangle extends Rectangle { + final Color color; + + ColoredRectangle( + this.color, + super.width, + super.height, + ); +} +``` -It is almost always wrong to return `null` for a `Future`. Most of the time the -developer simply forgot to put an `async` keyword on the function. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1104.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1104.md index 77148f88..e786e351 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1104.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1104.md @@ -1,25 +1,28 @@ --- -title: "Provide a deprecation message, via @Deprecated(\"message\")." -verbose_name: "provide_deprecation_message" +title: "Missing whitespace between adjacent strings" +verbose_name: "missing_whitespace_between_adjacent_strings" category: "antipattern" weight: 70 severity: "major" --- -**DO** specify a deprecation message (with migration instructions and/or a -removal schedule) in the Deprecation constructor. +Add a trailing whitespace to prevent missing whitespace between adjacent +strings. + +With long text split across adjacent strings it's easy to forget a whitespace +between strings. **BAD:** ```dart -@deprecated -void oldFunction(arg1, arg2) {} +var s = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed' + 'do eiusmod tempor incididunt ut labore et dolore magna'; ``` **GOOD:** ```dart -@Deprecated(""" -[oldFunction] is being deprecated in favor of [newFunction] (with slightly -different parameters; see [newFunction] for more information). [oldFunction] -will be removed on or after the 4.0.0 release. -""") -void oldFunction(arg1, arg2) {} +var s = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed ' + 'do eiusmod tempor incididunt ut labore et dolore magna'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1105.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1105.md index 5a820e2f..0ea1b986 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1105.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1105.md @@ -1,45 +1,22 @@ --- -title: "Prefer 'for' elements when building maps from iterables." -verbose_name: "prefer_for_elements_to_map_fromIterable" +title: "Avoid leading underscores for library prefixes" +verbose_name: "no_leading_underscores_for_library_prefixes" category: "antipattern" weight: 70 severity: "major" --- -When building maps from iterables, it is preferable to use 'for' elements. - -Using 'for' elements brings several benefits including: - -- Performance -- Flexibility -- Readability -- Improved type inference -- Improved interaction with null safety - +**DON'T** use a leading underscore for library prefixes. +There is no concept of "private" for library prefixes. When one of those has a +name that starts with an underscore, it sends a confusing signal to the reader. +To avoid that, don't use leading underscores in those names. **BAD:** ```dart -Map.fromIterable( - kAllGalleryDemos, - key: (demo) => '${demo.routeName}', - value: (demo) => demo.buildRoute, -); - +import 'dart:core' as _core; ``` **GOOD:** ```dart -return { - for (var demo in kAllGalleryDemos) - '${demo.routeName}': demo.buildRoute, -}; +import 'dart:core' as core; ``` -**GOOD:** -```dart -// Map is not required, type is inferred automatically. -final pizzaRecipients = { - ...studentLeaders, - for (var student in classG) - if (student.isPassing) student.id: student, -}; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1106.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1106.md index dc3bf7ff..f76b2b64 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1106.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1106.md @@ -1,21 +1,42 @@ --- -title: "Do use sound null safety." -verbose_name: "enable_null_safety" +title: "Avoid leading underscores for local identifiers" +verbose_name: "no_leading_underscores_for_local_identifiers" category: "antipattern" weight: 70 severity: "major" --- -**DO** use sound null safety, by not specifying a dart version lower than `2.12`. +**DON'T** use a leading underscore for identifiers that aren't private. Dart +uses a leading underscore in an identifier to mark members and top-level +declarations as private. This trains users to associate a leading underscore +with one of those kinds of declarations. They see `_` and think "private". +There is no concept of "private" for local variables or parameters. When one of +those has a name that starts with an underscore, it sends a confusing signal to +the reader. To avoid that, don't use leading underscores in those names. + +**EXCEPTION:**: An unused parameter can be named `_`, `__`, `___`, etc. This is +common practice in callbacks where you are passed a value but you don't need +to use it. Giving it a name that consists solely of underscores is the idiomatic +way to indicate that the value isn't used. **BAD:** ```dart -// @dart=2.8 -a() { +void print(String _name) { + var _size = _name.length; + ... } ``` - **GOOD:** + ```dart -b() { +void print(String name) { + var size = name.length; + ... } ``` + +**OK:** + +```dart +[1,2,3].map((_) => print('Hello')); +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1107.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1107.md index ccc5cf59..2f800ca6 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1107.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1107.md @@ -1,28 +1,29 @@ --- -title: "Prefer using `??=` over testing for null." -verbose_name: "prefer_conditional_assignment" +title: "Don't compare booleans to boolean literals" +verbose_name: "no_literal_bool_comparisons" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** using `??=` over testing for null. +From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-true-or-false-in-equality-operations): -As Dart has the `??=` operator, it is advisable to use it where applicable to -improve the brevity of your code. +**DON'T** use `true` or `false` in equality operations. + +This lint applies only if the expression is of a non-nullable `bool` type. **BAD:** ```dart -String get fullName { - if (_fullName == null) { - _fullName = getFullUserName(this); - } - return _fullName; +if (someBool == true) { +} +while (someBool == false) { } ``` **GOOD:** ```dart -String get fullName { - return _fullName ??= getFullUserName(this); +if (someBool) { +} +while (!someBool) { } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1108.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1108.md index f123b834..f208f31f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1108.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1108.md @@ -1,40 +1,34 @@ --- -title: "Don't access members with `this` unless avoiding shadowing." -verbose_name: "unnecessary_this" +title: "Avoid calling toString() on runtimeType" +verbose_name: "no_runtimeType_toString" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-this-when-not-needed-to-avoid-shadowing): - -**DON'T** use `this` when not needed to avoid shadowing. +Calling `toString` on a runtime type is a non-trivial operation that can +negatively impact performance. It's better to avoid it. **BAD:** ```dart -class Box { - int value; - void update(int newValue) { - this.value = newValue; - } +class A { + String toString() => '$runtimeType()'; } ``` **GOOD:** ```dart -class Box { - int value; - void update(int newValue) { - value = newValue; - } +class A { + String toString() => 'A()'; } ``` -**GOOD:** -```dart -class Box { - int value; - void update(int value) { - this.value = value; - } -} -``` +This lint has some exceptions where performance is not a problem or where real +type information is more important than performance: + +* in an assertion +* in a throw expression +* in a catch clause +* in a mixin declaration +* in an abstract class declaration + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1109.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1109.md index c9b689cb..3efee8fa 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1109.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1109.md @@ -1,27 +1,25 @@ --- -title: "Use `isEmpty` for Iterables and Maps." -verbose_name: "prefer_is_empty" +title: "Name non-constant identifiers using lowerCamelCase" +verbose_name: "non_constant_identifier_names" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use `length` to see if a collection is empty. +**DO** name non-constant identifiers using lowerCamelCase. -The `Iterable` contract does not require that a collection know its length or be -able to provide it in constant time. Calling `length` just to see if the -collection contains anything can be painfully slow. - -Instead, there are faster and more readable getters: `isEmpty` and -`isNotEmpty`. Use the one that doesn't require you to negate the result. - -**BAD:** -```dart -if (lunchBox.length == 0) return 'so hungry...'; -if (words.length != 0) return words.join(' '); -``` +Class members, top-level definitions, variables, parameters, named parameters +and named constructors should capitalize the first letter of each word +except the first word, and use no separators. **GOOD:** ```dart -if (lunchBox.isEmpty) return 'so hungry...'; -if (words.isNotEmpty) return words.join(' '); +var item; + +HttpRequest httpRequest; + +align(clearItems) { + // ... +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1110.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1110.md index a0221ba8..0eacf285 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1110.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1110.md @@ -1,35 +1,28 @@ --- -title: "Attach library doc comments to library directives." -verbose_name: "dangling_library_doc_comments" +title: "Noop primitive operations" +verbose_name: "noop_primitive_operations" category: "antipattern" weight: 70 severity: "major" --- -Attach library doc comments (with `///`) to library directives, rather than -leaving them dangling near the top of a library. +Some operations on primitive types are idempotent and can be removed. **BAD:** -```dart -/// This is a great library. -import 'package:math'; -``` ```dart -/// This is a great library. +doubleValue.toDouble(); -class C {} -``` - -**GOOD:** -```dart -/// This is a great library. -library; +intValue.toInt(); +intValue.round(); +intValue.ceil(); +intValue.floor(); +intValue.truncate(); -import 'package:math'; +string.toString(); +string = 'hello\n' + 'world\n' + ''; // useless empty string -class C {} +'string with ${x.toString()}'; ``` -**NOTE:** An unnamed library, like `library;` above, is only supported in Dart -2.19 and later. Code which might run in earlier versions of Dart will need to -provide a name in the `library` directive. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1111.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1111.md index 3319a25b..eb46c72d 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1111.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1111.md @@ -1,34 +1,35 @@ --- -title: "Prefer defining constructors instead of static methods to create instances." -verbose_name: "prefer_constructors_over_static_methods" +title: "Don't use null check on a potentially nullable type parameter" +verbose_name: "null_check_on_nullable_type_parameter" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** defining constructors instead of static methods to create instances. +**DON'T** use null check on a potentially nullable type parameter. -In most cases, it makes more sense to use a named constructor rather than a -static method because it makes instantiation clearer. +Given a generic type parameter `T` which has a nullable bound (e.g. the default +bound of `Object?`), it is very easy to introduce erroneous null checks when +working with a variable of type `T?`. Specifically, it is not uncommon to have +`T? x;` and want to assert that `x` has been set to a valid value of type `T`. +A common mistake is to do so using `x!`. This is almost always incorrect, since +if `T` is a nullable type, `x` may validly hold `null` as a value of type `T`. **BAD:** ```dart -class Point { - num x, y; - Point(this.x, this.y); - static Point polar(num theta, num radius) { - return Point(radius * math.cos(theta), - radius * math.sin(theta)); - } +T run(T callback()) { + T? result; + (() { result = callback(); })(); + return result!; } ``` **GOOD:** ```dart -class Point { - num x, y; - Point(this.x, this.y); - Point.polar(num theta, num radius) - : x = radius * math.cos(theta), - y = radius * math.sin(theta); +T run(T callback()) { + T? result; + (() { result = callback(); })(); + return result as T; } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1112.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1112.md index 697f9bfd..b4b48130 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1112.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1112.md @@ -1,23 +1,74 @@ --- -title: "Prefer relative imports for files in `lib/`." -verbose_name: "prefer_relative_imports" -category: "bug-risk" +title: "Do not pass `null` as an argument where a closure is expected" +verbose_name: "null_closures" +category: "antipattern" weight: 70 severity: "major" --- -**PREFER** relative imports for files in `lib/`. +**DON'T** pass `null` as an argument where a closure is expected. -When mixing relative and absolute imports it's possible to create confusion -where the same member gets imported in two different ways. One way to avoid -that is to ensure you consistently use relative imports for files within the -`lib/` directory. +Often a closure that is passed to a method will only be called conditionally, +so that tests and "happy path" production calls do not reveal that `null` will +result in an exception being thrown. + +This rule only catches null literals being passed where closures are expected +in the following locations: + +#### Constructors + +* From `dart:async` + * `Future` at the 0th positional parameter + * `Future.microtask` at the 0th positional parameter + * `Future.sync` at the 0th positional parameter + * `Timer` at the 0th positional parameter + * `Timer.periodic` at the 1st positional parameter +* From `dart:core` + * `List.generate` at the 1st positional parameter + +#### Static functions + +* From `dart:async` + * `scheduleMicrotask` at the 0th positional parameter + * `Future.doWhile` at the 0th positional parameter + * `Future.forEach` at the 0th positional parameter + * `Future.wait` at the named parameter `cleanup` + * `Timer.run` at the 0th positional parameter + +#### Instance methods + +* From `dart:async` + * `Future.then` at the 0th positional parameter + * `Future.complete` at the 0th positional parameter +* From `dart:collection` + * `Queue.removeWhere` at the 0th positional parameter + * `Queue.retain + * `Iterable.firstWhere` at the 0th positional parameter, and the named + parameter `orElse` + * `Iterable.forEach` at the 0th positional parameter + * `Iterable.fold` at the 1st positional parameter + * `Iterable.lastWhere` at the 0th positional parameter, and the named + parameter `orElse` + * `Iterable.map` at the 0th positional parameter + * `Iterable.reduce` at the 0th positional parameter + * `Iterable.singleWhere` at the 0th positional parameter, and the named + parameter `orElse` + * `Iterable.skipWhile` at the 0th positional parameter + * `Iterable.takeWhile` at the 0th positional parameter + * `Iterable.where` at the 0th positional parameter + * `List.removeWhere` at the 0th positional parameter + * `List.retainWhere` at the 0th positional parameter + * `String.replaceAllMapped` at the 1st positional parameter + * `String.replaceFirstMapped` at the 1st positional parameter + * `String.splitMapJoin` at the named parameters `onMatch` and `onNonMatch` **BAD:** ```dart -import 'package:my_package/bar.dart'; +[1, 3, 5].firstWhere((e) => e.isOdd, orElse: null); ``` **GOOD:** ```dart -import 'bar.dart'; +[1, 3, 5].firstWhere((e) => e.isOdd, orElse: () => null); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1113.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1113.md index dc78500d..886ba2ad 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1113.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1113.md @@ -1,18 +1,56 @@ --- -title: "Use raw string to avoid escapes." -verbose_name: "use_raw_strings" +title: "Omit type annotations for local variables" +verbose_name: "omit_local_variable_types" category: "antipattern" weight: 70 severity: "major" --- -A raw string can be used to avoid escaping only backslashes and dollars. +**DON'T** redundantly type annotate initialized local variables. + +Local variables, especially in modern code where functions tend to be small, +have very little scope. Omitting the type focuses the reader's attention on the +more important *name* of the variable and its initialized value. **BAD:** ```dart -var s = 'A string with only \\ and \$'; +List> possibleDesserts(Set pantry) { + List> desserts = >[]; + for (final List recipe in cookbook) { + if (pantry.containsAll(recipe)) { + desserts.add(recipe); + } + } + + return desserts; +} ``` **GOOD:** ```dart -var s = r'A string with only \ and $'; +List> possibleDesserts(Set pantry) { + var desserts = >[]; + for (final recipe in cookbook) { + if (pantry.containsAll(recipe)) { + desserts.add(recipe); + } + } + + return desserts; +} ``` + +Sometimes the inferred type is not the type you want the variable to have. For +example, you may intend to assign values of other types later. In that case, +annotate the variable with the type you want. + +**GOOD:** +```dart +Widget build(BuildContext context) { + Widget result = Text('You won!'); + if (applyPadding) { + result = Padding(padding: EdgeInsets.all(8.0), child: result); + } + return result; +} +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1114.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1114.md index 271f6ffe..6f5f7706 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1114.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1114.md @@ -1,73 +1,30 @@ --- -title: "Private field could be final." -verbose_name: "prefer_final_fields" +title: "Avoid defining a one-member abstract class when a simple function will do" +verbose_name: "one_member_abstracts" category: "antipattern" weight: 70 severity: "major" --- -**DO** prefer declaring private fields as final if they are not reassigned later -in the library. +From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-a-one-member-abstract-class-when-a-simple-function-will-do): -Declaring fields as final when possible is a good practice because it helps -avoid accidental reassignments and allows the compiler to do optimizations. +**AVOID** defining a one-member abstract class when a simple function will do. -**BAD:** -```dart -class BadImmutable { - var _label = 'hola mundo! BadImmutable'; // LINT - var label = 'hola mundo! BadImmutable'; // OK -} -``` +Unlike Java, Dart has first-class functions, closures, and a nice light syntax +for using them. If all you need is something like a callback, just use a +function. If you're defining a class and it only has a single abstract member +with a meaningless name like `call` or `invoke`, there is a good chance +you just want a function. **BAD:** ```dart -class MultipleMutable { - var _label = 'hola mundo! GoodMutable', _offender = 'mumble mumble!'; // LINT - var _someOther; // LINT - - MultipleMutable() : _someOther = 5; - - MultipleMutable(this._someOther); - - void changeLabel() { - _label= 'hello world! GoodMutable'; - } -} -``` - -**GOOD:** -```dart -class GoodImmutable { - final label = 'hola mundo! BadImmutable', bla = 5; // OK - final _label = 'hola mundo! BadImmutable', _bla = 5; // OK +abstract class Predicate { + bool test(item); } ``` **GOOD:** ```dart -class GoodMutable { - var _label = 'hola mundo! GoodMutable'; - - void changeLabel() { - _label = 'hello world! GoodMutable'; - } -} +typedef Predicate = bool Function(item); ``` -**BAD:** -```dart -class AssignedInAllConstructors { - var _label; // LINT - AssignedInAllConstructors(this._label); - AssignedInAllConstructors.withDefault() : _label = 'Hello'; -} -``` -**GOOD:** -```dart -class NotAssignedInAllConstructors { - var _label; // OK - NotAssignedInAllConstructors(); - NotAssignedInAllConstructors.withDefault() : _label = 'Hello'; -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1115.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1115.md index 135741aa..48ab7cf8 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1115.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1115.md @@ -1,18 +1,30 @@ --- -title: "Avoid using web-only libraries outside Flutter web plugin packages." -verbose_name: "avoid_web_libraries_in_flutter" -category: "bug-risk" +title: "Only throw instances of classes extending either Exception or Error" +verbose_name: "only_throw_errors" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using web libraries, `dart:html`, `dart:js` and -`dart:js_util` in Flutter packages that are not web plugins. These libraries are -not supported outside a web context; functionality that depends on them will -fail at runtime in Flutter mobile, and their use is generally discouraged in -Flutter web. +**DO** throw only instances of classes that extend `dart.core.Error` or +`dart.core.Exception`. -Web library access *is* allowed in: +Throwing instances that do not extend `Error` or `Exception` is a bad practice; +doing this is usually a hack for something that should be implemented more +thoroughly. + +**BAD:** +```dart +void throwString() { + throw 'hello world!'; // LINT +} +``` + +**GOOD:** +```dart +void throwArgumentError() { + Error error = ArgumentError('oh!'); + throw error; // OK +} +``` -* plugin packages that declare `web` as a supported context -otherwise, imports of `dart:html`, `dart:js` and `dart:js_util` are disallowed. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1116.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1116.md index 21e2f503..79bf758c 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1116.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1116.md @@ -1,41 +1,59 @@ --- -title: "Start the name of the method with to/_to or as/_as if applicable." -verbose_name: "use_to_and_as_if_applicable" +title: "Don't override fields" +verbose_name: "overridden_fields" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/design#prefer-naming-a-method-to___-if-it-copies-the-objects-state-to-a-new-object): +**DON'T** override fields. -**PREFER** naming a method `to___()` if it copies the object's state to a new -object. - -**PREFER** naming a method `as___()` if it returns a different representation -backed by the original object. +Overriding fields is almost always done unintentionally. Regardless, it is a +bad practice to do so. **BAD:** ```dart -class Bar { - Foo myMethod() { - return Foo.from(this); - } +class Base { + Object field = 'lorem'; + + Object something = 'change'; +} + +class Bad1 extends Base { + @override + final field = 'ipsum'; // LINT +} + +class Bad2 extends Base { + @override + Object something = 'done'; // LINT } ``` **GOOD:** ```dart -class Bar { - Foo toFoo() { - return Foo.from(this); - } +class Base { + Object field = 'lorem'; + + Object something = 'change'; +} + +class Ok extends Base { + Object newField; // OK + + final Object newFinal = 'ignore'; // OK } ``` **GOOD:** ```dart -class Bar { - Foo asFoo() { - return Foo.from(this); - } +abstract class BaseLoggingHandler { + Base transformer; +} + +class LogPrintHandler implements BaseLoggingHandler { + @override + Derived transformer; // OK } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1117.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1117.md index 29bf19e5..af89bf1c 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1117.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1117.md @@ -1,36 +1,53 @@ --- -title: "Prefer double quotes where they won't require escape sequences." -verbose_name: "prefer_double_quotes" +title: "Provide doc comments for all public APIs" +verbose_name: "package_api_docs" category: "antipattern" weight: 70 severity: "major" --- -**DO** use double quotes where they wouldn't require additional escapes. +**DO** provide doc comments for all public APIs. -That means strings with a double quote may use apostrophes so that the double -quote isn't escaped (note: we don't lint the other way around, ie, a double -quoted string with an escaped double quote is not flagged). +As described in the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files), +public APIs consist in everything in your package's `lib` folder, minus +implementation files in `lib/src`, adding elements explicitly exported with an +`export` directive. -It's also rare, but possible, to have strings within string interpolations. In -this case, its much more readable to use a single quote somewhere. So single -quotes are allowed either within, or containing, an interpolated string literal. -Arguably strings within string interpolations should be its own type of lint. +For example, given `lib/foo.dart`: +```dart +export 'src/bar.dart' show Bar; +export 'src/baz.dart'; + +class Foo { } + +class _Foo { } +``` +its API includes: + +* `Foo` (but not `_Foo`) +* `Bar` (exported) and +* all *public* elements in `src/baz.dart` + +All public API members should be documented with `///` doc-style comments. **BAD:** ```dart -useStrings( - 'should be double quote', - r'should be double quote', - r\'''should be double quotes\''') +class Bar { + void bar(); +} ``` **GOOD:** ```dart -useStrings( - "should be double quote", - r"should be double quote", - r"""should be double quotes""", - 'ok with " inside', - 'nested \${a ? "strings" : "can"} be wrapped by a double quote', - "and nested \${a ? 'strings' : 'can be double quoted themselves'}"); +/// A Foo. +abstract class Foo { + /// Start foo-ing. + void start() => _start(); + + _start(); +} ``` + +Advice for writing good doc comments can be found in the +[Doc Writing Guidelines](https://dart.dev/effective-dart/documentation). + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1118.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1118.md index c39a2614..504aad0a 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1118.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1118.md @@ -1,35 +1,40 @@ --- -title: "Don't use `final` for local variables." -verbose_name: "unnecessary_final" +title: "Prefix library names with the package name and a dot-separated path" +verbose_name: "package_prefixed_library_names" category: "antipattern" weight: 70 severity: "major" --- -Use `var`, not `final`, when declaring local variables. +**DO** prefix library names with the package name and a dot-separated path. -Per [Effective Dart](https://dart.dev/effective-dart/usage#do-follow-a-consistent-rule-for-var-and-final-on-local-variables), -there are two styles in wide use. This rule enforces the `var` style. -For the alternative style that prefers `final`, enable `prefer_final_locals` -and `prefer_final_in_for_each` instead. +This guideline helps avoid the warnings you get when two libraries have the same +name. Here are the rules we recommend: -For fields, `final` is always recommended; see the rule `prefer_final_fields`. +* Prefix all library names with the package name. +* Make the entry library have the same name as the package. +* For all other libraries in a package, after the package name add the +dot-separated path to the library's Dart file. +* For libraries under `lib`, omit the top directory name. -**BAD:** -```dart -void badMethod() { - final label = 'Final or var?'; - for (final char in ['v', 'a', 'r']) { - print(char); - } -} -``` +For example, say the package name is `my_package`. Here are the library names +for various files in the package: **GOOD:** ```dart -void goodMethod() { - var label = 'Final or var?'; - for (var char in ['v', 'a', 'r']) { - print(char); - } -} +// In lib/my_package.dart +library my_package; + +// In lib/other.dart +library my_package.other; + +// In lib/foo/bar.dart +library my_package.foo.bar; + +// In example/foo/bar.dart +library my_package.example.foo.bar; + +// In lib/src/private.dart +library my_package.src.private; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1119.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1119.md index 14fac62c..db1bb5ca 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1119.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1119.md @@ -1,34 +1,74 @@ --- -title: "Avoid empty statements." -verbose_name: "empty_statements" -category: "bug-risk" +title: "Don't reassign references to parameters of functions or methods" +verbose_name: "parameter_assignments" +category: "antipattern" weight: 70 severity: "major" --- -**AVOID** empty statements. +**DON'T** assign new values to parameters of methods or functions. -Empty statements almost always indicate a bug. +Assigning new values to parameters is generally a bad practice unless an +operator such as `??=` is used. Otherwise, arbitrarily reassigning parameters +is usually a mistake. -For example, +**BAD:** +```dart +void badFunction(int parameter) { // LINT + parameter = 4; +} +``` **BAD:** ```dart -if (complicated.expression.foo()); - bar(); +void badFunction(int required, {int optional: 42}) { // LINT + optional ??= 8; +} ``` -Formatted with `dart format` the bug becomes obvious: +**BAD:** +```dart +void badFunctionPositional(int required, [int optional = 42]) { // LINT + optional ??= 8; +} +``` +**BAD:** ```dart -if (complicated.expression.foo()) ; -bar(); +class A { + void badMethod(int parameter) { // LINT + parameter = 4; + } +} +``` +**GOOD:** +```dart +void ok(String parameter) { + print(parameter); +} ``` -Better to avoid the empty statement altogether. +**GOOD:** +```dart +void actuallyGood(int required, {int optional}) { // OK + optional ??= ...; +} +``` **GOOD:** ```dart -if (complicated.expression.foo()) - bar(); +void actuallyGoodPositional(int required, [int optional]) { // OK + optional ??= ...; +} ``` + +**GOOD:** +```dart +class A { + void ok(String parameter) { + print(parameter); + } +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1120.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1120.md index d17ccb11..04c1774e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1120.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1120.md @@ -1,20 +1,24 @@ --- -title: "Avoid private typedef functions." -verbose_name: "avoid_private_typedef_functions" +title: "Use adjacent strings to concatenate string literals" +verbose_name: "prefer_adjacent_string_concatenation" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** private typedef functions used only once. Prefer inline function -syntax. +**DO** use adjacent strings to concatenate string literals. **BAD:** ```dart -typedef void _F(); -m(_F f); +raiseAlarm( + 'ERROR: Parts of the spaceship are on fire. Other ' + + 'parts are overrun by martians. Unclear which are which.'); ``` **GOOD:** ```dart -m(void Function() f); +raiseAlarm( + 'ERROR: Parts of the spaceship are on fire. Other ' + 'parts are overrun by martians. Unclear which are which.'); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1121.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1121.md index 4aa06231..c07bb412 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1121.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1121.md @@ -1,36 +1,26 @@ --- -title: "Use trailing commas for all function calls and declarations." -verbose_name: "require_trailing_commas" +title: "Prefer putting asserts in initializer lists" +verbose_name: "prefer_asserts_in_initializer_lists" category: "antipattern" weight: 70 severity: "major" --- -**DO** use trailing commas for all function calls and declarations unless the -function call or definition, from the start of the function name up to the -closing parenthesis, fits in a single line. +**DO** put asserts in initializer lists. **BAD:** ```dart -void run() { - method('does not fit on one line', - 'test test test test test test test test test test test'); +class A { + A(int a) { + assert(a != 0); + } } ``` **GOOD:** ```dart -void run() { - method( - 'does not fit on one line', - 'test test test test test test test test test test test', - ); +class A { + A(int a) : assert(a != 0); } ``` -**EXCEPTION:** If the final parameter/argument is positional (vs named) and is -either a function literal implemented using curly braces, a literal map, a -literal set or a literal array. This exception only applies if the final -parameter does not fit entirely on one line. -**NOTE:** This lint rule assumes `dart format` has been run over the code and -may produce false positives until that has happened. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1122.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1122.md index 33774e72..b58a8888 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1122.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1122.md @@ -1,66 +1,33 @@ --- -title: "Define case clauses for all constants in enum-like classes." -verbose_name: "exhaustive_cases" +title: "Prefer asserts with message" +verbose_name: "prefer_asserts_with_message" category: "antipattern" weight: 70 severity: "major" --- -Switching on instances of enum-like classes should be exhaustive. - -Enum-like classes are defined as concrete (non-abstract) classes that have: - * only private non-factory constructors - * two or more static const fields whose type is the enclosing class and - * no subclasses of the class in the defining library - -**DO** define case clauses for all constants in enum-like classes. +When assertions fail it's not always simple to understand why. Adding a message +to the `assert` helps the developer to understand why the AssertionError occurs. **BAD:** ```dart -class EnumLike { - final int i; - const EnumLike._(this.i); - - static const e = EnumLike._(1); - static const f = EnumLike._(2); - static const g = EnumLike._(3); +f(a) { + assert(a != null); } -void bad(EnumLike e) { - // Missing case. - switch(e) { // LINT - case EnumLike.e : - print('e'); - break; - case EnumLike.f : - print('f'); - break; - } +class A { + A(a) : assert(a != null); } ``` **GOOD:** ```dart -class EnumLike { - final int i; - const EnumLike._(this.i); - - static const e = EnumLike._(1); - static const f = EnumLike._(2); - static const g = EnumLike._(3); +f(a) { + assert(a != null, 'a must not be null'); } -void ok(EnumLike e) { - // All cases covered. - switch(e) { // OK - case EnumLike.e : - print('e'); - break; - case EnumLike.f : - print('f'); - break; - case EnumLike.g : - print('g'); - break; - } +class A { + A(a) : assert(a != null, 'a must not be null'); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1123.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1123.md index 7f347200..a3a0a690 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1123.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1123.md @@ -1,35 +1,48 @@ --- -title: "Prefer using lowerCamelCase for constant names." -verbose_name: "constant_identifier_names" +title: "Use collection literals when possible" +verbose_name: "prefer_collection_literals" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** using lowerCamelCase for constant names. - -In new code, use `lowerCamelCase` for constant variables, including enum values. - -In existing code that uses `ALL_CAPS_WITH_UNDERSCORES` for constants, you may -continue to use all caps to stay consistent. +**DO** use collection literals when possible. **BAD:** ```dart -const PI = 3.14; -const kDefaultTimeout = 1000; -final URL_SCHEME = RegExp('^([a-z]+):'); - -class Dice { - static final NUMBER_GENERATOR = Random(); -} +var addresses = Map(); +var uniqueNames = Set(); +var ids = LinkedHashSet(); +var coordinates = LinkedHashMap(); ``` **GOOD:** ```dart -const pi = 3.14; -const defaultTimeout = 1000; -final urlScheme = RegExp('^([a-z]+):'); +var addresses = {}; +var uniqueNames = {}; +var ids = {}; +var coordinates = {}; +``` + +**EXCEPTIONS:** -class Dice { - static final numberGenerator = Random(); +When a `LinkedHashSet` or `LinkedHashMap` is expected, a collection literal is +not preferred (or allowed). + +```dart +void main() { + LinkedHashSet linkedHashSet = LinkedHashSet.from([1, 2, 3]); // OK + LinkedHashMap linkedHashMap = LinkedHashMap(); // OK + + printSet(LinkedHashSet()); // LINT + printHashSet(LinkedHashSet()); // OK + + printMap(LinkedHashMap()); // LINT + printHashMap(LinkedHashMap()); // OK } + +void printSet(Set ids) => print('$ids!'); +void printHashSet(LinkedHashSet ids) => printSet(ids); +void printMap(Map map) => print('$map!'); +void printHashMap(LinkedHashMap map) => printMap(map); ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1124.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1124.md index d1caef31..908699c5 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1124.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1124.md @@ -1,37 +1,30 @@ --- -title: "Avoid async functions that return void." -verbose_name: "avoid_void_async" +title: "Prefer using `??=` over testing for null" +verbose_name: "prefer_conditional_assignment" category: "antipattern" weight: 70 severity: "major" --- -**DO** mark async functions as returning Future. +**PREFER** using `??=` over testing for null. -When declaring an async method or function which does not return a value, -declare that it returns `Future` and not just `void`. +As Dart has the `??=` operator, it is advisable to use it where applicable to +improve the brevity of your code. **BAD:** ```dart -void f() async {} -void f2() async => null; +String get fullName { + if (_fullName == null) { + _fullName = getFullUserName(this); + } + return _fullName; +} ``` **GOOD:** ```dart -Future f() async {} -Future f2() async => null; +String get fullName { + return _fullName ??= getFullUserName(this); +} ``` -**EXCEPTION:** - -An exception is made for top-level `main` functions, where the `Future` -annotation *can* (and generally should) be dropped in favor of `void`. - -**GOOD:** -```dart -Future f() async {} -void main() async { - await f(); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1125.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1125.md index 8e44f490..040083ed 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1125.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1125.md @@ -1,61 +1,46 @@ --- -title: "Test type arguments in operator ==(Object other)." -verbose_name: "test_types_in_equals" -category: "bug-risk" +title: "Prefer const with constant constructors" +verbose_name: "prefer_const_constructors" +category: "antipattern" weight: 70 severity: "major" --- -**DO** test type arguments in operator ==(Object other). +**PREFER** using `const` for instantiating constant constructors. -Not testing types might result in null pointer exceptions which will be -unexpected for consumers of your class. +If a constructor can be invoked as const to produce a canonicalized instance, +it's preferable to do so. **BAD:** ```dart -class Field { +class A { + const A(); } -class Bad { - final Field someField; - - Bad(this.someField); - - @override - bool operator ==(Object other) { - Bad otherBad = other as Bad; // LINT - bool areEqual = otherBad != null && otherBad.someField == someField; - return areEqual; - } - - @override - int get hashCode { - return someField.hashCode; - } +void accessA() { + A a = new A(); } ``` **GOOD:** ```dart -class Field { +class A { + const A(); } -class Good { - final Field someField; - - Good(this.someField); +void accessA() { + A a = const A(); +} +``` - @override - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - return other is Good && - this.someField == other.someField; - } +**GOOD:** +```dart +class A { + final int x; - @override - int get hashCode { - return someField.hashCode; - } + const A(this.x); } + +A foo(int x) => new A(x); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1126.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1126.md index d1f18c87..abd247d4 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1126.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1126.md @@ -1,5 +1,5 @@ --- -title: "Prefer declaring const constructors on `@immutable` classes." +title: "Prefer declaring const constructors on `@immutable` classes" verbose_name: "prefer_const_constructors_in_immutables" category: "antipattern" weight: 70 @@ -27,3 +27,5 @@ class A { const A(this.a); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1127.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1127.md index bd1b80d0..eedba797 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1127.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1127.md @@ -1,35 +1,31 @@ --- -title: "Use `forEach` to only apply a function to all the elements." -verbose_name: "prefer_foreach" +title: "Prefer const over final for declarations" +verbose_name: "prefer_const_declarations" category: "antipattern" weight: 70 severity: "major" --- -**DO** use `forEach` if you are only going to apply a function or a method -to all the elements of an iterable. +**PREFER** using `const` for const declarations. -Using `forEach` when you are only going to apply a function or method to all -elements of an iterable is a good practice because it makes your code more -terse. +Const declarations are more hot-reload friendly and allow to use const +constructors if an instantiation references this declaration. **BAD:** ```dart -for (final key in map.keys.toList()) { - map.remove(key); +final o = const []; + +class A { + static final o = const []; } ``` **GOOD:** ```dart -map.keys.toList().forEach(map.remove); -``` +const o = []; -**NOTE:** Replacing a for each statement with a forEach call may change the -behavior in the case where there are side-effects on the iterable itself. -```dart -for (final v in myList) { - foo().f(v); // This code invokes foo() many times. +class A { + static const o = []; } - -myList.forEach(foo().f); // But this one invokes foo() just once. ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1128.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1128.md index 91766888..2f408d48 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1128.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1128.md @@ -1,26 +1,29 @@ --- -title: "Name types using UpperCamelCase." -verbose_name: "camel_case_types" +title: "Prefer const literals as parameters of constructors on @immutable classes" +verbose_name: "prefer_const_literals_to_create_immutables" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/style#do-name-types-using-uppercamelcase): +**PREFER** using `const` for instantiating list, map and set literals used as +parameters in immutable class instantiations. -**DO** name types using UpperCamelCase. +**BAD:** +```dart +@immutable +class A { + A(this.v); + final v; +} -Classes and typedefs should capitalize the first letter of each word (including -the first word), and use no separators. +A a1 = new A([1]); +A a2 = new A({}); +``` **GOOD:** ```dart -class SliderMenu { - // ... -} +A a1 = new A(const [1]); +A a2 = new A(const {}); +``` -class HttpRequest { - // ... -} -typedef num Adder(num x, num y); -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1129.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1129.md index c75e4bc7..ef9fa1c2 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1129.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1129.md @@ -1,22 +1,35 @@ --- -title: "Use valid regular expression syntax." -verbose_name: "valid_regexps" -category: "bug-risk" +title: "Prefer defining constructors instead of static methods to create instances" +verbose_name: "prefer_constructors_over_static_methods" +category: "antipattern" weight: 70 severity: "major" --- -**DO** use valid regular expression syntax when creating regular expression -instances. +**PREFER** defining constructors instead of static methods to create instances. -Regular expressions created with invalid syntax will throw a `FormatException` -at runtime so should be avoided. +In most cases, it makes more sense to use a named constructor rather than a +static method because it makes instantiation clearer. **BAD:** ```dart -print(RegExp(r'(').hasMatch('foo()')); +class Point { + num x, y; + Point(this.x, this.y); + static Point polar(num theta, num radius) { + return Point(radius * math.cos(theta), + radius * math.sin(theta)); + } +} ``` **GOOD:** ```dart -print(RegExp(r'\(').hasMatch('foo()')); +class Point { + num x, y; + Point(this.x, this.y); + Point.polar(num theta, num radius) + : x = radius * math.cos(theta), + y = radius * math.sin(theta); +} ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1130.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1130.md index b1a3e60a..e28e5683 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1130.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1130.md @@ -1,26 +1,25 @@ --- -title: "Unnecessary null aware operator on extension on a nullable type." -verbose_name: "unnecessary_null_aware_operator_on_extension_on_nullable" +title: "Use contains for `List` and `String` instances" +verbose_name: "prefer_contains" category: "antipattern" weight: 70 severity: "major" --- -Avoid null aware operators for members defined in an extension on a nullable type. +**DON'T** use `indexOf` to see if a collection contains an element. -**BAD:** +Calling `indexOf` to see if a collection contains something is difficult to read +and may have poor performance. + +Instead, prefer `contains`. +**BAD:** ```dart -extension E on int? { - int m() => 1; -} -f(int? i) => i?.m(); +if (lunchBox.indexOf('sandwich') == -1) return 'so hungry...'; ``` **GOOD:** - ```dart -extension E on int? { - int m() => 1; -} -f(int? i) => i.m(); +if (!lunchBox.contains('sandwich')) return 'so hungry...'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1131.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1131.md index 55baff0f..3a035e78 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1131.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1131.md @@ -1,43 +1,38 @@ --- -title: "Separate the control structure expression from its statement." -verbose_name: "always_put_control_body_on_new_line" +title: "Prefer double quotes where they won't require escape sequences" +verbose_name: "prefer_double_quotes" category: "antipattern" weight: 70 severity: "major" --- -From the [style guide for the flutter repo](https://flutter.dev/style-guide/): +**DO** use double quotes where they wouldn't require additional escapes. -**DO** separate the control structure expression from its statement. +That means strings with a double quote may use apostrophes so that the double +quote isn't escaped (note: we don't lint the other way around, ie, a double +quoted string with an escaped double quote is not flagged). -Don't put the statement part of an `if`, `for`, `while`, `do` on the same line -as the expression, even if it is short. Doing so makes it unclear that there -is relevant code there. This is especially important for early returns. +It's also rare, but possible, to have strings within string interpolations. In +this case, its much more readable to use a single quote somewhere. So single +quotes are allowed either within, or containing, an interpolated string literal. +Arguably strings within string interpolations should be its own type of lint. **BAD:** ```dart -if (notReady) return; - -if (notReady) - return; -else print('ok') - -while (condition) i += 1; +useStrings( + 'should be double quote', + r'should be double quote', + r'''should be double quotes''') ``` **GOOD:** ```dart -if (notReady) - return; - -if (notReady) - return; -else - print('ok') - -while (condition) - i += 1; +useStrings( + "should be double quote", + r"should be double quote", + r"""should be double quotes""", + 'ok with " inside', + 'nested ${a ? "strings" : "can"} be wrapped by a double quote', + "and nested ${a ? 'strings' : 'can be double quoted themselves'}"); ``` -Note that this rule can conflict with the -[Dart formatter](https://dart.dev/tools/dart-format), and should not be enabled -when the Dart formatter is used. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1132.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1132.md index 65e00a99..e365c446 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1132.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1132.md @@ -1,38 +1,46 @@ --- -title: "Don't use the Null type, unless you are positive that you don't want void." -verbose_name: "prefer_void_to_null" -category: "bug-risk" +title: "Use => for short members whose body is a single return statement" +verbose_name: "prefer_expression_function_bodies" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use the type Null where void would work. +**CONSIDER** using => for short members whose body is a single return statement. **BAD:** ```dart -Null f() {} -Future f() {} -Stream f() {} -f(Null x) {} +get width { + return right - left; +} ``` -**GOOD:** +**BAD:** ```dart -void f() {} -Future f() {} -Stream f() {} -f(void x) {} +bool ready(num time) { + return minTime == null || minTime <= time; +} ``` -Some exceptions include formulating special function types: +**BAD:** +```dart +containsValue(String value) { + return getValues().contains(value); +} +``` +**GOOD:** ```dart -Null Function(Null, Null); +get width => right - left; ``` -and for making empty literals which are safe to pass into read-only locations -for any type of map or list: +**GOOD:** +```dart +bool ready(num time) => minTime == null || minTime <= time; +``` +**GOOD:** ```dart -[]; -{}; +containsValue(String value) => getValues().contains(value); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1133.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1133.md index 90de2590..27aac07a 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1133.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1133.md @@ -1,26 +1,74 @@ --- -title: "Sort unnamed constructor declarations first." -verbose_name: "sort_unnamed_constructors_first" +title: "Private field could be final" +verbose_name: "prefer_final_fields" category: "antipattern" weight: 70 severity: "major" --- -**DO** sort unnamed constructor declarations first, before named ones. +**DO** prefer declaring private fields as final if they are not reassigned later +in the library. + +Declaring fields as final when possible is a good practice because it helps +avoid accidental reassignments and allows the compiler to do optimizations. + +**BAD:** +```dart +class BadImmutable { + var _label = 'hola mundo! BadImmutable'; // LINT + var label = 'hola mundo! BadImmutable'; // OK +} +``` + +**BAD:** +```dart +class MultipleMutable { + var _label = 'hola mundo! GoodMutable', _offender = 'mumble mumble!'; // LINT + var _someOther; // LINT + + MultipleMutable() : _someOther = 5; + + MultipleMutable(this._someOther); + + void changeLabel() { + _label= 'hello world! GoodMutable'; + } +} +``` + +**GOOD:** +```dart +class GoodImmutable { + final label = 'hola mundo! BadImmutable', bla = 5; // OK + final _label = 'hola mundo! BadImmutable', _bla = 5; // OK +} +``` + +**GOOD:** +```dart +class GoodMutable { + var _label = 'hola mundo! GoodMutable'; + + void changeLabel() { + _label = 'hello world! GoodMutable'; + } +} +``` **BAD:** ```dart -class _PriorityItem { - factory _PriorityItem.forName(bool isStatic, String name, _MemberKind kind) => ... - _PriorityItem(this.isStatic, this.kind, this.isPrivate); - ... +class AssignedInAllConstructors { + var _label; // LINT + AssignedInAllConstructors(this._label); + AssignedInAllConstructors.withDefault() : _label = 'Hello'; } ``` **GOOD:** ```dart -abstract class CancelableFuture implements Future { - factory CancelableFuture(computation()) => ... - factory CancelableFuture.delayed(Duration duration, [computation()]) => ... - ... +class NotAssignedInAllConstructors { + var _label; // OK + NotAssignedInAllConstructors(); + NotAssignedInAllConstructors.withDefault() : _label = 'Hello'; } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1134.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1134.md index bf87f265..6ef330a9 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1134.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1134.md @@ -1,34 +1,37 @@ --- -title: "Don't use more than one case with same value." -verbose_name: "no_duplicate_case_values" -category: "bug-risk" +title: "Prefer final in for-each loop variable if reference is not reassigned" +verbose_name: "prefer_final_in_for_each" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use more than one case with same value. +**DO** prefer declaring for-each loop variables as final if they are not +reassigned later in the code. -This is usually a typo or changed value of constant. +Declaring for-each loop variables as final when possible is a good practice +because it helps avoid accidental reassignments and allows the compiler to do +optimizations. **BAD:** ```dart -const int A = 1; -switch (v) { - case 1: - case 2: - case A: - case 2: +for (var element in elements) { // LINT + print('Element: $element'); } ``` **GOOD:** ```dart -const int A = 1; -switch (v) { - case A: - case 2: +for (final element in elements) { + print('Element: $element'); } ``` -NOTE: this lint only reports duplicate cases in libraries opted in to Dart 2.19 -and below. In Dart 3.0 and after, duplicate cases are reported as dead code -by the analyzer. +**GOOD:** +```dart +for (var element in elements) { + element = element + element; + print('Element: $element'); +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1135.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1135.md index 2615b633..868ef52e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1135.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1135.md @@ -1,34 +1,40 @@ --- -title: "Avoid returning null for void." -verbose_name: "avoid_returning_null_for_void" +title: "Prefer final for variable declarations if they are not reassigned" +verbose_name: "prefer_final_locals" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** returning null for void. +**DO** prefer declaring variables as final if they are not reassigned later in +the code. -In a large variety of languages `void` as return type is used to indicate that -a function doesn't return anything. Dart allows returning `null` in functions -with `void` return type but it also allow using `return;` without specifying any -value. To have a consistent way you should not return `null` and only use an -empty return. +Declaring variables as final when possible is a good practice because it helps +avoid accidental reassignments and allows the compiler to do optimizations. **BAD:** ```dart -void f1() { - return null; -} -Future f2() async { - return null; +void badMethod() { + var label = 'hola mundo! badMethod'; // LINT + print(label); } ``` **GOOD:** ```dart -void f1() { - return; +void goodMethod() { + final label = 'hola mundo! goodMethod'; + print(label); } -Future f2() async { - return; +``` + +**GOOD:** +```dart +void mutableCase() { + var label = 'hola mundo! mutableCase'; + print(label); + label = 'hello world'; + print(label); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1136.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1136.md index 750e26d9..a640c8b6 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1136.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1136.md @@ -1,105 +1,57 @@ --- -title: "Don't assign a variable to itself." -verbose_name: "no_self_assignments" -category: "bug-risk" +title: "Prefer final for parameter declarations if they are not reassigned" +verbose_name: "prefer_final_parameters" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** assign a variable to itself. Usually this is a mistake. +**DO** prefer declaring parameters as final if they are not reassigned in +the function body. + +Declaring parameters as final when possible is a good practice because it helps +avoid accidental reassignments. **BAD:** ```dart -class C { - int x; - - C(int x) { - x = x; - } +void badParameter(String label) { // LINT + print(label); } ``` **GOOD:** ```dart -class C { - int x; - - C(int x) : x = x; -} -``` - -**GOOD:** -```dart -class C { - int x; - - C(int x) { - this.x = x; - } +void goodParameter(final String label) { // OK + print(label); } ``` **BAD:** ```dart -class C { - int _x = 5; - - int get x => _x; - - set x(int x) { - _x = x; - _customUpdateLogic(); - } - - void _customUpdateLogic() { - print('updated'); - } - - void example() { - x = x; - } -} +void badExpression(int value) => print(value); // LINT ``` **GOOD:** ```dart -class C { - int _x = 5; - - int get x => _x; - - set x(int x) { - _x = x; - _customUpdateLogic(); - } - - void _customUpdateLogic() { - print('updated'); - } - - void example() { - _customUpdateLogic(); - } -} +void goodExpression(final int value) => print(value); // OK ``` **BAD:** ```dart -class C { - int x = 5; - - void update(C other) { - this.x = this.x; - } -} +[1, 4, 6, 8].forEach((value) => print(value + 2)); // LINT ``` **GOOD:** ```dart -class C { - int x = 5; +[1, 4, 6, 8].forEach((final value) => print(value + 2)); // OK +``` - void update(C other) { - this.x = other.x; - } +**GOOD:** +```dart +void mutableParameter(String label) { // OK + print(label); + label = 'Hello Linter!'; + print(label); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1137.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1137.md index fedb9a42..9f8cd139 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1137.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1137.md @@ -1,28 +1,46 @@ --- -title: "Avoid positional boolean parameters." -verbose_name: "avoid_positional_boolean_parameters" +title: "Prefer 'for' elements when building maps from iterables" +verbose_name: "prefer_for_elements_to_map_fromIterable" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** positional boolean parameters. +When building maps from iterables, it is preferable to use 'for' elements. + +Using 'for' elements brings several benefits including: + +- Performance +- Flexibility +- Readability +- Improved type inference +- Improved interaction with null safety -Positional boolean parameters are a bad practice because they are very -ambiguous. Using named boolean parameters is much more readable because it -inherently describes what the boolean value represents. **BAD:** ```dart -Task(true); -Task(false); -ListBox(false, true, true); -Button(false); +Map.fromIterable( + kAllGalleryDemos, + key: (demo) => '${demo.routeName}', + value: (demo) => demo.buildRoute, +); + +``` + +**GOOD:** +```dart +return { + for (var demo in kAllGalleryDemos) + '${demo.routeName}': demo.buildRoute, +}; ``` **GOOD:** ```dart -Task.oneShot(); -Task.repeating(); -ListBox(scroll: true, showScrollbars: true); -Button(ButtonState.enabled); +// Map is not required, type is inferred automatically. +final pizzaRecipients = { + ...studentLeaders, + for (var student in classG) + if (student.isPassing) student.id: student, +}; ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1138.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1138.md index 2dd0c3d4..09aca8d8 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1138.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1138.md @@ -1,31 +1,37 @@ --- -title: "Unreachable top-level members in executable libraries." -verbose_name: "unreachable_from_main" +title: "Use `forEach` to only apply a function to all the elements" +verbose_name: "prefer_foreach" category: "antipattern" weight: 70 severity: "major" --- -Top-level members and static members in an executable library should be used -directly inside this library. An executable library is a library that contains -a `main` top-level function or that contains a top-level function annotated with -`@pragma('vm:entry-point')`). Executable libraries are not usually imported -and it's better to avoid defining unused members. +**DO** use `forEach` if you are only going to apply a function or a method +to all the elements of an iterable. -This rule assumes that an executable library isn't imported by other files -except to execute its `main` function. +Using `forEach` when you are only going to apply a function or method to all +elements of an iterable is a good practice because it makes your code more +terse. **BAD:** - ```dart -main() {} -void f() {} +for (final key in map.keys.toList()) { + map.remove(key); +} ``` **GOOD:** +```dart +map.keys.toList().forEach(map.remove); +``` +**NOTE:** Replacing a for each statement with a forEach call may change the +behavior in the case where there are side-effects on the iterable itself. ```dart -main() { - f(); +for (final v in myList) { + foo().f(v); // This code invokes foo() many times. } -void f() {} + +myList.forEach(foo().f); // But this one invokes foo() just once. ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1139.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1139.md index fb1a7201..b9e0cc12 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1139.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1139.md @@ -1,18 +1,31 @@ --- -title: "Avoid single cascade in expression statements." -verbose_name: "avoid_single_cascade_in_expression_statements" +title: "Use a function declaration to bind a function to a name" +verbose_name: "prefer_function_declarations_over_variables" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** single cascade in expression statements. +**DO** use a function declaration to bind a function to a name. + +As Dart allows local function declarations, it is a good practice to use them in +the place of function literals. **BAD:** ```dart -o..m(); +void main() { + var localFunction = () { + ... + }; +} ``` **GOOD:** ```dart -o.m(); +void main() { + localFunction() { + ... + } +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1140.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1140.md index 236d1f03..43710c5b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1140.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1140.md @@ -1,33 +1,28 @@ --- -title: "Unnecessary `.new` constructor name." -verbose_name: "unnecessary_constructor_name" +title: "Prefer generic function type aliases" +verbose_name: "prefer_generic_function_type_aliases" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** using the default unnamed Constructor over `.new`. +**PREFER** generic function type aliases. -Given a class `C`, the named unnamed constructor `C.new` refers to the same -constructor as the unnamed `C`. As such it adds nothing but visual noise to -invocations and should be avoided (unless being used to identify a constructor -tear-off). +With the introduction of generic functions, function type aliases +(`typedef void F()`) couldn't express all of the possible kinds of +parameterization that users might want to express. Generic function type aliases +(`typedef F = void Function()`) fixed that issue. + +For consistency and readability reasons, it's better to only use one syntax and +thus prefer generic function type aliases. **BAD:** ```dart -class A { - A.new(); // LINT -} - -var a = A.new(); // LINT +typedef void F(); ``` **GOOD:** ```dart -class A { - A.ok(); -} - -var a = A(); -var aa = A.ok(); -var makeA = A.new; +typedef F = void Function(); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1141.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1141.md index 1684c934..f18f0870 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1141.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1141.md @@ -1,23 +1,20 @@ --- -title: "Missing conditional import." -verbose_name: "conditional_uri_does_not_exist" +title: "Prefer if elements to conditional expressions where possible" +verbose_name: "prefer_if_elements_to_conditional_expressions" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** reference files that do not exist in conditional imports. - -Code may fail at runtime if the condition evaluates such that the missing file -needs to be imported. +When building collections, it is preferable to use `if` elements rather than +conditionals. **BAD:** ```dart -import 'file_that_does_exist.dart' - if (condition) 'file_that_does_not_exist.dart'; +var list = ['a', 'b', condition ? 'c' : null].where((e) => e != null).toList(); ``` **GOOD:** ```dart -import 'file_that_does_exist.dart' - if (condition) 'file_that_also_does_exist.dart'; +var list = ['a', 'b', if (condition) 'c']; ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1142.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1142.md index f567b9bf..3e73c922 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1142.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1142.md @@ -1,25 +1,21 @@ --- -title: "Use `isNotEmpty` for Iterables and Maps." -verbose_name: "prefer_is_not_empty" +title: "Prefer using if null operators" +verbose_name: "prefer_if_null_operators" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** `x.isNotEmpty` to `!x.isEmpty` for `Iterable` and `Map` instances. - -When testing whether an iterable or map is empty, prefer `isNotEmpty` over -`!isEmpty` to improve code readability. +**PREFER** using if null operators instead of null checks in conditional +expressions. **BAD:** ```dart -if (!sources.isEmpty) { - process(sources); -} +v = a == null ? b : a; ``` **GOOD:** ```dart -if (todo.isNotEmpty) { - sendResults(request, todo.isEmpty); -} +v = a ?? b; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1143.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1143.md index 03ecedde..9aeef0b2 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1143.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1143.md @@ -1,104 +1,79 @@ --- -title: "Adhere to Effective Dart Guide directives sorting conventions." -verbose_name: "directives_ordering" +title: "Use initializing formals when possible" +verbose_name: "prefer_initializing_formals" category: "antipattern" weight: 70 severity: "major" --- -**DO** follow the directive ordering conventions in -[Effective Dart](https://dart.dev/effective-dart/style#ordering): +**DO** use initializing formals when possible. -**DO** place `dart:` imports before other imports. +Using initializing formals when possible makes your code more terse. **BAD:** ```dart -import 'package:bar/bar.dart'; -import 'package:foo/foo.dart'; - -import 'dart:async'; // LINT -import 'dart:html'; // LINT -``` - -**BAD:** -```dart -import 'dart:html'; // OK -import 'package:bar/bar.dart'; - -import 'dart:async'; // LINT -import 'package:foo/foo.dart'; +class Point { + num x, y; + Point(num x, num y) { + this.x = x; + this.y = y; + } +} ``` **GOOD:** ```dart -import 'dart:async'; // OK -import 'dart:html'; // OK - -import 'package:bar/bar.dart'; -import 'package:foo/foo.dart'; -``` - -**DO** place `package:` imports before relative imports. - -**BAD:** -```dart -import 'a.dart'; -import 'b.dart'; - -import 'package:bar/bar.dart'; // LINT -import 'package:foo/foo.dart'; // LINT +class Point { + num x, y; + Point(this.x, this.y); +} ``` **BAD:** ```dart -import 'package:bar/bar.dart'; // OK -import 'a.dart'; - -import 'package:foo/foo.dart'; // LINT -import 'b.dart'; +class Point { + num x, y; + Point({num x, num y}) { + this.x = x; + this.y = y; + } +} ``` **GOOD:** ```dart -import 'package:bar/bar.dart'; // OK -import 'package:foo/foo.dart'; // OK - -import 'a.dart'; -import 'b.dart'; +class Point { + num x, y; + Point({this.x, this.y}); +} ``` -**DO** specify exports in a separate section after all imports. +**NOTE:** +This rule will not generate a lint for named parameters unless the parameter +name and the field name are the same. The reason for this is that resolving +such a lint would require either renaming the field or renaming the parameter, +and both of those actions would potentially be a breaking change. For example, +the following will not generate a lint: -**BAD:** ```dart -import 'src/error.dart'; -export 'src/error.dart'; // LINT -import 'src/string_source.dart'; -``` - -**GOOD:** -```dart -import 'src/error.dart'; -import 'src/string_source.dart'; - -export 'src/error.dart'; // OK +class Point { + bool isEnabled; + Point({bool enabled}) { + this.isEnabled = enabled; // OK + } +} ``` -**DO** sort sections alphabetically. +**NOTE:** +Also note that it is possible to enforce a type that is stricter than the +initialized field with an initializing formal parameter. In the following +example the unnamed `Bid` constructor requires a non-null `int` despite +`amount` being declared nullable (`int?`). -**BAD:** ```dart -import 'package:foo/bar.dart'; // OK -import 'package:bar/bar.dart'; // LINT - -import 'a/b.dart'; // OK -import 'a.dart'; // LINT +class Bid { + final int? amount; + Bid(int this.amount); + Bid.pass() : amount = null; +} ``` -**GOOD:** -```dart -import 'package:bar/bar.dart'; // OK -import 'package:foo/bar.dart'; // OK - -import 'a.dart'; // OK -import 'a/b.dart'; // OK -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1144.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1144.md index 4cc7ed28..2035573d 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1144.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1144.md @@ -1,29 +1,23 @@ --- -title: "Prefer const over final for declarations." -verbose_name: "prefer_const_declarations" +title: "Inline list item declarations where possible" +verbose_name: "prefer_inlined_adds" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** using `const` for const declarations. +Declare elements in list literals inline, rather than using `add` and +`addAll` methods where possible. -Const declarations are more hot-reload friendly and allow to use const -constructors if an instantiation references this declaration. **BAD:** ```dart -final o = const []; - -class A { - static final o = const []; -} +var l = ['a']..add('b')..add('c'); +var l2 = ['a']..addAll(['b', 'c']); ``` **GOOD:** ```dart -const o = []; - -class A { - static const o = []; -} +var l = ['a', 'b', 'c']; +var l2 = ['a', 'b', 'c']; ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1145.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1145.md index ca4c8e0a..514ecd58 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1145.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1145.md @@ -1,20 +1,28 @@ --- -title: "Don't declare multiple variables on a single line." -verbose_name: "avoid_multiple_declarations_per_line" +title: "Prefer int literals over double literals" +verbose_name: "prefer_int_literals" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** declare multiple variables on a single line. +**DO** use int literals rather than the corresponding double literal. **BAD:** ```dart -String? foo, bar, baz; +const double myDouble = 8.0; +final anotherDouble = myDouble + 7.0e2; +main() { + someMethod(6.0); +} ``` **GOOD:** ```dart -String? foo; -String? bar; -String? baz; +const double myDouble = 8; +final anotherDouble = myDouble + 700; +main() { + someMethod(6); +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1146.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1146.md index 221a2eaf..1f483ab3 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1146.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1146.md @@ -1,22 +1,23 @@ --- -title: "Don't assign to void." -verbose_name: "void_checks" +title: "Use interpolation to compose strings and values" +verbose_name: "prefer_interpolation_to_compose_strings" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** assign to void. +**PREFER** using interpolation to compose strings and values. + +Using interpolation when composing strings and values is usually easier to write +and read than concatenation. **BAD:** ```dart -class A { - T value; - void test(T arg) { } -} +'Hello, ' + person.name + ' from ' + person.city + '.'; +``` -void main() { - A a = A(); - a.value = 1; // LINT - a.test(1); // LINT -} +**GOOD:** +```dart +'Hello, ${person.name} from ${person.city}.' ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1147.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1147.md index 72583e56..634a309a 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1147.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1147.md @@ -1,62 +1,29 @@ --- -title: "Use spread collections when possible." -verbose_name: "prefer_spread_collections" +title: "Use `isEmpty` for Iterables and Maps" +verbose_name: "prefer_is_empty" category: "antipattern" weight: 70 severity: "major" --- -Use spread collections when possible. +**DON'T** use `length` to see if a collection is empty. -Collection literals are excellent when you want to create a new collection out -of individual items. But, when existing items are already stored in another -collection, spread collection syntax leads to simpler code. +The `Iterable` contract does not require that a collection know its length or be +able to provide it in constant time. Calling `length` just to see if the +collection contains anything can be painfully slow. -**BAD:** - -```dart -Widget build(BuildContext context) { - return CupertinoPageScaffold( - child: ListView( - children: [ - Tab2Header(), - ]..addAll(buildTab2Conversation()), - ), - ); -} -``` - -```dart -var ints = [1, 2, 3]; -print(['a']..addAll(ints.map((i) => i.toString()))..addAll(['c'])); -``` +Instead, there are faster and more readable getters: `isEmpty` and +`isNotEmpty`. Use the one that doesn't require you to negate the result. +**BAD:** ```dart -var things; -var l = ['a']..addAll(things ?? const []); +if (lunchBox.length == 0) return 'so hungry...'; +if (words.length != 0) return words.join(' '); ``` - **GOOD:** - ```dart -Widget build(BuildContext context) { - return CupertinoPageScaffold( - child: ListView( - children: [ - Tab2Header(), - ...buildTab2Conversation(), - ], - ), - ); -} +if (lunchBox.isEmpty) return 'so hungry...'; +if (words.isNotEmpty) return words.join(' '); ``` -```dart -var ints = [1, 2, 3]; -print(['a', ...ints.map((i) => i.toString()), 'c'); -``` -```dart -var things; -var l = ['a', ...?things]; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1148.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1148.md index 49b0f650..eb81c9d0 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1148.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1148.md @@ -1,23 +1,27 @@ --- -title: "Name non-constant identifiers using lowerCamelCase." -verbose_name: "non_constant_identifier_names" +title: "Use `isNotEmpty` for Iterables and Maps" +verbose_name: "prefer_is_not_empty" category: "antipattern" weight: 70 severity: "major" --- -**DO** name non-constant identifiers using lowerCamelCase. +**PREFER** `x.isNotEmpty` to `!x.isEmpty` for `Iterable` and `Map` instances. -Class members, top-level definitions, variables, parameters, named parameters -and named constructors should capitalize the first letter of each word -except the first word, and use no separators. +When testing whether an iterable or map is empty, prefer `isNotEmpty` over +`!isEmpty` to improve code readability. -**GOOD:** +**BAD:** ```dart -var item; - -HttpRequest httpRequest; +if (!sources.isEmpty) { + process(sources); +} +``` -align(clearItems) { - // ... +**GOOD:** +```dart +if (todo.isNotEmpty) { + sendResults(request, todo.isEmpty); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1149.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1149.md index 7b211f2a..dc9b53e3 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1149.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1149.md @@ -1,41 +1,24 @@ --- -title: "Use `DecoratedBox`." -verbose_name: "use_decorated_box" +title: "Prefer is! operator" +verbose_name: "prefer_is_not_operator" category: "antipattern" weight: 70 severity: "major" --- -**DO** use `DecoratedBox` when `Container` has only a `Decoration`. - -A `Container` is a heavier Widget than a `DecoratedBox`, and as bonus, -`DecoratedBox` has a `const` constructor. +When checking if an object is not of a specified type, it is preferable to use the 'is!' operator. **BAD:** ```dart -Widget buildArea() { - return Container( - decoration: const BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.all( - Radius.circular(5), - ), - ), - child: const Text('...'), - ); +if (!(foo is Foo)) { + ... } ``` **GOOD:** ```dart -Widget buildArea() { - return const DecoratedBox( - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.all( - Radius.circular(5), - ), - ), - child: Text('...'), - ); +if (foo is! Foo) { + ... } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1150.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1150.md index 2704032b..a3413bbf 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1150.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1150.md @@ -1,26 +1,20 @@ --- -title: "Prefer generic function type aliases." -verbose_name: "prefer_generic_function_type_aliases" +title: "Prefer to use whereType on iterable" +verbose_name: "prefer_iterable_whereType" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** generic function type aliases. - -With the introduction of generic functions, function type aliases -(`typedef void F()`) couldn't express all of the possible kinds of -parameterization that users might want to express. Generic function type aliases -(`typedef F = void Function()`) fixed that issue. - -For consistency and readability reasons, it's better to only use one syntax and -thus prefer generic function type aliases. +**PREFER** `iterable.whereType()` over `iterable.where((e) => e is T)`. **BAD:** ```dart -typedef void F(); +iterable.where((e) => e is MyClass); ``` **GOOD:** ```dart -typedef F = void Function(); +iterable.whereType(); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1151.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1151.md index 04aee0fe..6a94cd7b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1151.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1151.md @@ -1,32 +1,25 @@ --- -title: "Avoid calling toString() on runtimeType." -verbose_name: "no_runtimeType_toString" +title: "Prefer using mixins" +verbose_name: "prefer_mixin" category: "antipattern" weight: 70 severity: "major" --- -Calling `toString` on a runtime type is a non-trivial operation that can -negatively impact performance. It's better to avoid it. +Dart 2.1 introduced a new syntax for mixins that provides a safe way for a mixin +to invoke inherited members using `super`. The new style of mixins should always +be used for types that are to be mixed in. As a result, this lint will flag any +uses of a class in a `with` clause. **BAD:** ```dart -class A { - String toString() => '$runtimeType()'; -} +class A {} +class B extends Object with A {} ``` -**GOOD:** +**OK:** ```dart -class A { - String toString() => 'A()'; -} +mixin M {} +class C with M {} ``` -This lint has some exceptions where performance is not a problem or where real -type information is more important than performance: -* in an assertion -* in a throw expression -* in a catch clause -* in a mixin declaration -* in an abstract class declaration diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1152.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1152.md index f38b6f90..b5aa206f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1152.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1152.md @@ -1,26 +1,21 @@ --- -title: "Sort constructor declarations before other members." -verbose_name: "sort_constructors_first" +title: "Prefer null aware method calls" +verbose_name: "prefer_null_aware_method_calls" category: "antipattern" weight: 70 severity: "major" --- -**DO** sort constructor declarations before other members. +Instead of checking nullability of a function/method `f` before calling it you +can use `f?.call()`. **BAD:** ```dart -abstract class Visitor { - double value; - visitSomething(Something s); - Visitor(); -} +if (f != null) f!(); ``` **GOOD:** ```dart -abstract class Animation { - const Animation(this.value); - double value; - void addListener(VoidCallback listener); -} +f?.call(); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1153.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1153.md index 9cb649f2..c27f6fd8 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1153.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1153.md @@ -1,47 +1,21 @@ --- -title: "Missing deprecated annotation." -verbose_name: "deprecated_consistency" +title: "Prefer using null aware operators" +verbose_name: "prefer_null_aware_operators" category: "antipattern" weight: 70 severity: "major" --- -**DO** apply `@Deprecated()` consistently: - -- if a class is deprecated, its constructors should also be deprecated. -- if a field is deprecated, the constructor parameter pointing to it should also - be deprecated. -- if a constructor parameter pointing to a field is deprecated, the field should - also be deprecated. +**PREFER** using null aware operators instead of null checks in conditional +expressions. **BAD:** ```dart -@deprecated -class A { - A(); -} - -class B { - B({this.field}); - @deprecated - Object field; -} +v = a == null ? null : a.b; ``` **GOOD:** ```dart -@deprecated -class A { - @deprecated - A(); -} +v = a?.b; +``` -class B { - B({@deprecated this.field}); - @deprecated - Object field; -} -class C extends B { - C({@deprecated super.field}); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1154.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1154.md index 6fb4e1e4..28593867 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1154.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1154.md @@ -1,41 +1,38 @@ --- -title: "Annotate redeclared members." -verbose_name: "annotate_redeclares" +title: "Only use double quotes for strings containing single quotes" +verbose_name: "prefer_single_quotes" category: "antipattern" weight: 70 severity: "major" --- -**DO** annotate redeclared members. +**DO** use single quotes where they wouldn't require additional escapes. -This practice improves code readability and helps protect against -unintentionally redeclaring members or being surprised when a member ceases to -redeclare (due for example to a rename refactoring). +That means strings with an apostrophe may use double quotes so that the +apostrophe isn't escaped (note: we don't lint the other way around, ie, a single +quoted string with an escaped apostrophe is not flagged). + +It's also rare, but possible, to have strings within string interpolations. In +this case, its much more readable to use a double quote somewhere. So double +quotes are allowed either within, or containing, an interpolated string literal. +Arguably strings within string interpolations should be its own type of lint. **BAD:** ```dart -class C { - void f() { } -} - -extension type E(C c) implements C { - void f() { - ... - } -} +useStrings( + "should be single quote", + r"should be single quote", + r"""should be single quotes""") ``` **GOOD:** ```dart -import 'package:meta/meta.dart'; +useStrings( + 'should be single quote', + r'should be single quote', + r'''should be single quotes''', + "here's ok", + "nested ${a ? 'strings' : 'can'} be wrapped by a double quote", + 'and nested ${a ? "strings" : "can be double quoted themselves"}'); +``` -class C { - void f() { } -} -extension type E(C c) implements C { - @redeclare - void f() { - ... - } -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1155.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1155.md index ec7bb956..9dc729a4 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1155.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1155.md @@ -1,26 +1,63 @@ --- -title: "Use if-null operators to convert nulls to bools." -verbose_name: "use_if_null_to_convert_nulls_to_bools" +title: "Use spread collections when possible" +verbose_name: "prefer_spread_collections" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/usage#prefer-using--to-convert-null-to-a-boolean-value): +Use spread collections when possible. -Use if-null operators to convert nulls to bools. +Collection literals are excellent when you want to create a new collection out +of individual items. But, when existing items are already stored in another +collection, spread collection syntax leads to simpler code. **BAD:** + ```dart -if (nullableBool == true) { -} -if (nullableBool != false) { +Widget build(BuildContext context) { + return CupertinoPageScaffold( + child: ListView( + children: [ + Tab2Header(), + ]..addAll(buildTab2Conversation()), + ), + ); } ``` +```dart +var ints = [1, 2, 3]; +print(['a']..addAll(ints.map((i) => i.toString()))..addAll(['c'])); +``` + +```dart +var things; +var l = ['a']..addAll(things ?? const []); +``` + + **GOOD:** + ```dart -if (nullableBool ?? false) { -} -if (nullableBool ?? true) { +Widget build(BuildContext context) { + return CupertinoPageScaffold( + child: ListView( + children: [ + Tab2Header(), + ...buildTab2Conversation(), + ], + ), + ); } ``` + +```dart +var ints = [1, 2, 3]; +print(['a', ...ints.map((i) => i.toString()), 'c'); +``` + +```dart +var things; +var l = ['a', ...?things]; +``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1156.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1156.md index eee2ca5d..b7303cc0 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1156.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1156.md @@ -1,28 +1,51 @@ --- -title: "Property getter recursively returns itself." -verbose_name: "recursive_getters" +title: "Prefer typing uninitialized variables and fields" +verbose_name: "prefer_typing_uninitialized_variables" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** create recursive getters. +**PREFER** specifying a type annotation for uninitialized variables and fields. -Recursive getters are getters which return themselves as a value. This is -usually a typo. +Forgoing type annotations for uninitialized variables is a bad practice because +you may accidentally assign them to a type that you didn't originally intend to. **BAD:** ```dart -int get field => field; // LINT +class BadClass { + static var bar; // LINT + var foo; // LINT + + void method() { + var bar; // LINT + bar = 5; + print(bar); + } +} ``` **BAD:** ```dart -int get otherField { - return otherField; // LINT +void aFunction() { + var bar; // LINT + bar = 5; + ... } ``` **GOOD:** ```dart -int get field => _field; +class GoodClass { + static var bar = 7; + var foo = 42; + int baz; // OK + + void method() { + int baz; + var bar = 5; + ... + } +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1157.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1157.md index e9222d4c..07336440 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1157.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1157.md @@ -1,34 +1,27 @@ --- -title: "Avoid returning this from methods just to enable a fluent interface." -verbose_name: "avoid_returning_this" +title: "Provide a deprecation message, via @Deprecated("message")" +verbose_name: "provide_deprecation_message" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** returning this from methods just to enable a fluent interface. - -Returning `this` from a method is redundant; Dart has a cascade operator which -allows method chaining universally. - -Returning `this` is allowed for: - -- operators -- methods with a return type different of the current class -- methods defined in parent classes / mixins or interfaces -- methods defined in extensions +**DO** specify a deprecation message (with migration instructions and/or a +removal schedule) in the Deprecation constructor. **BAD:** ```dart -var buffer = StringBuffer() - .write('one') - .write('two') - .write('three'); +@deprecated +void oldFunction(arg1, arg2) {} ``` **GOOD:** ```dart -var buffer = StringBuffer() - ..write('one') - ..write('two') - ..write('three'); +@Deprecated(""" +[oldFunction] is being deprecated in favor of [newFunction] (with slightly +different parameters; see [newFunction] for more information). [oldFunction] +will be removed on or after the 4.0.0 release. +""") +void oldFunction(arg1, arg2) {} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1158.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1158.md index 6006995e..0c78bd20 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1158.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1158.md @@ -1,24 +1,54 @@ --- -title: "Name extensions using UpperCamelCase." -verbose_name: "camel_case_extensions" +title: "Document all public members" +verbose_name: "public_member_api_docs" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/style#do-name-extensions-using-uppercamelcase): +**DO** document all public members. -**DO** name extensions using `UpperCamelCase`. +All non-overriding public members should be documented with `///` doc-style +comments. -Extensions should capitalize the first letter of each word (including -the first word), and use no separators. +**BAD:** +```dart +class Bad { + void meh() { } +} +``` **GOOD:** ```dart -extension MyFancyList on List { - // ... +/// A good thing. +abstract class Good { + /// Start doing your thing. + void start() => _start(); + + _start(); } +``` + +In case a public member overrides a member it is up to the declaring member +to provide documentation. For example, in the following, `Sub` needn't +document `init` (though it certainly may, if there's need). -extension SmartIterable on Iterable { - // ... +**GOOD:** +```dart +/// Base of all things. +abstract class Base { + /// Initialize the base. + void init(); +} + +/// A sub base. +class Sub extends Base { + @override + void init() { ... } } ``` + +Note that consistent with `dart doc`, an exception to the rule is made when +documented getters have corresponding undocumented setters. In this case the +setters inherit the docs from the getters. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1159.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1159.md index 9e1c6007..b17b9df9 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1159.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1159.md @@ -1,30 +1,30 @@ --- -title: "Use `" -verbose_name: "empty_constructor_bodies" +title: "Property getter recursively returns itself" +verbose_name: "recursive_getters" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/usage#do-use--instead-of--for-empty-constructor-bodies): +**DON'T** create recursive getters. -**DO** use `;` instead of `{}` for empty constructor bodies. +Recursive getters are getters which return themselves as a value. This is +usually a typo. -In Dart, a constructor with an empty body can be terminated with just a -semicolon. This is required for const constructors. For consistency and -brevity, other constructors should also do this. +**BAD:** +```dart +int get field => field; // LINT +``` **BAD:** ```dart -class Point { - int x, y; - Point(this.x, this.y) {} +int get otherField { + return otherField; // LINT } ``` **GOOD:** ```dart -class Point { - int x, y; - Point(this.x, this.y); -} +int get field => _field; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1160.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1160.md index 5cb0c36a..3fc2e7ad 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1160.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1160.md @@ -1,20 +1,38 @@ --- -title: "Use a setter for operations that conceptually change a property." -verbose_name: "use_setters_to_change_properties" +title: "Use trailing commas for all function calls and declarations" +verbose_name: "require_trailing_commas" category: "antipattern" weight: 70 severity: "major" --- -**DO** use a setter for operations that conceptually change a property. +**DO** use trailing commas for all function calls and declarations unless the +function call or definition, from the start of the function name up to the +closing parenthesis, fits in a single line. **BAD:** ```dart -rectangle.setWidth(3); -button.setVisible(false); +void run() { + method('does not fit on one line', + 'test test test test test test test test test test test'); +} ``` **GOOD:** ```dart -rectangle.width = 3; -button.visible = false; +void run() { + method( + 'does not fit on one line', + 'test test test test test test test test test test test', + ); +} ``` + +**EXCEPTION:** If the final parameter/argument is positional (vs named) and is +either a function literal implemented using curly braces, a literal map, a +literal set or a literal array. This exception only applies if the final +parameter does not fit entirely on one line. + +**NOTE:** This lint rule assumes `dart format` has been run over the code and +may produce false positives until that has happened. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1161.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1161.md index f7894d65..0b5fb32e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1161.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1161.md @@ -1,37 +1,42 @@ --- -title: "Only reference in scope identifiers in doc comments." -verbose_name: "comment_references" -category: "bug-risk" +title: "SizedBox for whitespace" +verbose_name: "sized_box_for_whitespace" +category: "antipattern" weight: 70 severity: "major" --- -**DO** reference only in scope identifiers in doc comments. +Use SizedBox to add whitespace to a layout. -If you surround things like variable, method, or type names in square brackets, -then [`dart doc`](https://dart.dev/tools/dart-doc) will look -up the name and link to its docs. For this all to work, ensure that all -identifiers in docs wrapped in brackets are in scope. - -For example, assuming `outOfScopeId` is out of scope: +A `Container` is a heavier Widget than a `SizedBox`, and as bonus, `SizedBox` +has a `const` constructor. **BAD:** ```dart -/// Return true if [value] is larger than [outOfScopeId]. -bool isOutOfRange(int value) { ... } +Widget buildRow() { + return Row( + children: [ + const MyLogo(), + Container(width: 4), + const Expanded( + child: Text('...'), + ), + ], + ); +} ``` **GOOD:** ```dart -/// Return the larger of [a] or [b]. -int max_int(int a, int b) { ... } +Widget buildRow() { + return Row( + children: const [ + MyLogo(), + SizedBox(width: 4), + Expanded( + child: Text('...'), + ), + ], + ); +} ``` -Note that the square bracket comment format is designed to allow -comments to refer to declarations using a fairly natural format -but does not allow *arbitrary expressions*. In particular, code -references within square brackets can consist of either - -- a single identifier where the identifier is any identifier in scope for the comment (see the spec for what is in scope in doc comments), -- two identifiers separated by a period where the first identifier is the name of a class that is in scope and the second is the name of a member declared in the class, -- a single identifier followed by a pair of parentheses where the identifier is the name of a class that is in scope (used to refer to the unnamed constructor for the class), or -- two identifiers separated by a period and followed by a pair of parentheses where the first identifier is the name of a class that is in scope and the second is the name of a named constructor (not strictly necessary, but allowed for consistency). diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1162.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1162.md index 7f936c74..788751be 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1162.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1162.md @@ -1,39 +1,54 @@ --- -title: "Avoid relative imports for files in `lib/`." -verbose_name: "always_use_package_imports" -category: "bug-risk" +title: "Use SizedBox shrink and expand named constructors" +verbose_name: "sized_box_shrink_expand" +category: "antipattern" weight: 70 severity: "major" --- -**DO** avoid relative imports for files in `lib/`. +Use `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors +appropriately. -When mixing relative and absolute imports it's possible to create confusion -where the same member gets imported in two different ways. One way to avoid -that is to ensure you consistently use absolute imports for files within the -`lib/` directory. +Either the `SizedBox.shrink(...)` or `SizedBox.expand(...)` constructor should +be used instead of the more general `SizedBox(...)` constructor when one of the +named constructors capture the intent of the code more succinctly. -This is the opposite of 'prefer_relative_imports'. - -You can also use 'avoid_relative_lib_imports' to disallow relative imports of -files within `lib/` directory outside of it (for example `test/`). +**Examples** **BAD:** ```dart -import 'baz.dart'; - -import 'src/bag.dart' - -import '../lib/baz.dart'; +Widget buildLogo() { + return SizedBox( + height: 0, + width: 0, + child: const MyLogo(), + ); +} +``` -... +```dart +Widget buildLogo() { + return SizedBox( + height: double.infinity, + width: double.infinity, + child: const MyLogo(), + ); +} ``` **GOOD:** ```dart -import 'package:foo/bar.dart'; - -import 'package:foo/baz.dart'; +Widget buildLogo() { + return SizedBox.shrink( + child: const MyLogo(), + ); +} +``` -import 'package:foo/src/baz.dart'; -... +```dart +Widget buildLogo() { + return SizedBox.expand( + child: const MyLogo(), + ); +} ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1163.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1163.md index 452ea9cd..5fa1a364 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1163.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1163.md @@ -1,19 +1,29 @@ --- -title: "Prefer null aware method calls." -verbose_name: "prefer_null_aware_method_calls" +title: "Prefer using /// for doc comments" +verbose_name: "slash_for_doc_comments" category: "antipattern" weight: 70 severity: "major" --- -Instead of checking nullability of a function/method `f` before calling it you -can use `f?.call()`. +From [Effective Dart](https://dart.dev/effective-dart/documentation#do-use--doc-comments-to-document-members-and-types): -**BAD:** -```dart -if (f != null) f!(); -``` +**DO** use `///` for documentation comments. + +Although Dart supports two syntaxes of doc comments (`///` and `/**`), we +prefer using `///` for doc comments. **GOOD:** ```dart -f?.call(); +/// Parses a set of option strings. For each option: +/// +/// * If it is `null`, then it is ignored. +/// * If it is a string, then [validate] is called on it. +/// * If it is any other type, it is *not* validated. +void parse(List options) { + // ... +} ``` + +Within a doc comment, you can use markdown for formatting. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1164.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1164.md index 7d47398f..700252bf 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1164.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1164.md @@ -1,52 +1,75 @@ --- -title: "Use enums rather than classes that behave like enums." -verbose_name: "use_enums" +title: "Sort child properties last in widget instance creations" +verbose_name: "sort_child_properties_last" category: "antipattern" weight: 70 severity: "major" --- -Classes that look like enumerations should be declared as `enum`s. - -**DO** use enums where appropriate. - -Candidates for enums are classes that: - - * are concrete, - * are private or have only private generative constructors, - * have two or more static const fields with the same type as the class, - * have generative constructors that are only invoked at the top-level of the - initialization expression of these static fields, - * do not define `hashCode`, `==`, `values` or `index`, - * do not extend any class other than `Object`, and - * have no subclasses declared in the defining library. - -To learn more about creating and using these enums, check out -[Declaring enhanced enums](https://dart.dev/language/enums#declaring-enhanced-enums). +Sort child properties last in widget instance creations. This improves +readability and plays nicest with UI as Code visualization in IDEs with UI as +Code Guides in editors (such as IntelliJ) where Properties in the correct order +appear clearly associated with the constructor call and separated from the +children. **BAD:** ```dart -class LogPriority { - static const error = LogPriority._(1, 'Error'); - static const warning = LogPriority._(2, 'Warning'); - static const log = LogPriority._unknown('Log'); - - final String prefix; - final int priority; - const LogPriority._(this.priority, this.prefix); - const LogPriority._unknown(String prefix) : this._(-1, prefix); -} +return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + children: [ + Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.display1, + ), + ], + mainAxisAlignment: MainAxisAlignment.center, + ), + widthFactor: 0.5, + ), + floatingActionButton: FloatingActionButton( + child: Icon(Icons.add), + onPressed: _incrementCounter, + tooltip: 'Increment', + ), +); ``` **GOOD:** ```dart -enum LogPriority { - error(1, 'Error'), - warning(2, 'Warning'), - log.unknown('Log'); - - final String prefix; - final int priority; - const LogPriority(this.priority, this.prefix); - const LogPriority.unknown(String prefix) : this(-1, prefix); -} +return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + widthFactor: 0.5, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.display1, + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: Icon(Icons.add), + ), +); ``` + +Exception: It's allowed to have parameter with a function expression after the +`child` property. + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1165.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1165.md index 50279270..339ad141 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1165.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1165.md @@ -1,28 +1,28 @@ --- -title: "Don't import implementation files from another package." -verbose_name: "implementation_imports" +title: "Sort constructor declarations before other members" +verbose_name: "sort_constructors_first" category: "antipattern" weight: 70 severity: "major" --- -From the the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files): - -**DON'T** import implementation files from another package. - -The libraries inside `lib` are publicly visible: other packages are free to -import them. But much of a package's code is internal implementation libraries -that should only be imported and used by the package itself. Those go inside a -subdirectory of `lib` called `src`. You can create subdirectories in there if -it helps you organize things. - -You are free to import libraries that live in `lib/src` from within other Dart -code in the same package (like other libraries in `lib`, scripts in `bin`, -and tests) but you should never import from another package's `lib/src` -directory. Those files are not part of the package's public API, and they -might change in ways that could break your code. +**DO** sort constructor declarations before other members. **BAD:** ```dart -// In 'road_runner' -import 'package:acme/src/internals.dart'; +abstract class Visitor { + double value; + visitSomething(Something s); + Visitor(); +} +``` + +**GOOD:** +```dart +abstract class Animation { + const Animation(this.value); + double value; + void addListener(VoidCallback listener); +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1166.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1166.md index 9edd1b2f..6f1b50d9 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1166.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1166.md @@ -1,28 +1,28 @@ --- -title: "Await only futures." -verbose_name: "await_only_futures" +title: "Sort unnamed constructor declarations first" +verbose_name: "sort_unnamed_constructors_first" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using await on anything which is not a future. - -Await is allowed on the types: `Future`, `FutureOr`, `Future?`, -`FutureOr?` and `dynamic`. - -Further, using `await null` is specifically allowed as a way to introduce a -microtask delay. +**DO** sort unnamed constructor declarations first, before named ones. **BAD:** ```dart -main() async { - print(await 23); +class _PriorityItem { + factory _PriorityItem.forName(bool isStatic, String name, _MemberKind kind) => ... + _PriorityItem(this.isStatic, this.kind, this.isPrivate); + ... } ``` + **GOOD:** ```dart -main() async { - await null; // If a delay is really intended. - print(23); +abstract class CancelableFuture implements Future { + factory CancelableFuture(computation()) => ... + factory CancelableFuture.delayed(Duration duration, [computation()]) => ... + ... } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1167.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1167.md index ab3d2522..8a8f1569 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1167.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1167.md @@ -1,73 +1,38 @@ --- -title: "Sort child properties last in widget instance creations." -verbose_name: "sort_child_properties_last" +title: "Tighten type of initializing formal" +verbose_name: "tighten_type_of_initializing_formals" category: "antipattern" weight: 70 severity: "major" --- -Sort child properties last in widget instance creations. This improves -readability and plays nicest with UI as Code visualization in IDEs with UI as -Code Guides in editors (such as IntelliJ) where Properties in the correct order -appear clearly associated with the constructor call and separated from the -children. +Tighten the type of an initializing formal if a non-null assert exists. This +allows the type system to catch problems rather than have them only be caught at +run-time. **BAD:** ```dart -return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: Column( - children: [ - Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.display1, - ), - ], - mainAxisAlignment: MainAxisAlignment.center, - ), - widthFactor: 0.5, - ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - onPressed: _incrementCounter, - tooltip: 'Increment', - ), -); +class A { + A.c1(this.p) : assert(p != null); + A.c2(this.p); + final String? p; +} ``` **GOOD:** ```dart -return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - widthFactor: 0.5, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.display1, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: Icon(Icons.add), - ), -); +class A { + A.c1(String this.p); + A.c2(this.p); + final String? p; +} + +class B { + String? b; + B(this.b); +} + +class C extends B { + B(String super.b); +} ``` -Exception: It's allowed to have parameter with a function expression after the -`child` property. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1168.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1168.md index 14083de1..3e52c00a 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1168.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1168.md @@ -1,55 +1,42 @@ --- -title: "Omit type annotations for local variables." -verbose_name: "omit_local_variable_types" +title: "Type annotate public APIs" +verbose_name: "type_annotate_public_apis" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** redundantly type annotate initialized local variables. +From [Effective Dart](https://dart.dev/effective-dart/design#do-type-annotate-fields-and-top-level-variables-if-the-type-isnt-obvious): -Local variables, especially in modern code where functions tend to be small, -have very little scope. Omitting the type focuses the reader's attention on the -more important *name* of the variable and its initialized value. +**PREFER** type annotating public APIs. + +Type annotations are important documentation for how a library should be used. +Annotating the parameter and return types of public methods and functions helps +users understand what the API expects and what it provides. + +Note that if a public API accepts a range of values that Dart's type system +cannot express, then it is acceptable to leave that untyped. In that case, the +implicit `dynamic` is the correct type for the API. + +For code internal to a library (either private, or things like nested functions) +annotate where you feel it helps, but don't feel that you *must* provide them. **BAD:** ```dart -List> possibleDesserts(Set pantry) { - List> desserts = >[]; - for (final List recipe in cookbook) { - if (pantry.containsAll(recipe)) { - desserts.add(recipe); - } - } - - return desserts; +install(id, destination) { + // ... } ``` +Here, it's unclear what `id` is. A string? And what is `destination`? A string +or a `File` object? Is this method synchronous or asynchronous? + **GOOD:** ```dart -List> possibleDesserts(Set pantry) { - var desserts = >[]; - for (final recipe in cookbook) { - if (pantry.containsAll(recipe)) { - desserts.add(recipe); - } - } - - return desserts; +Future install(PackageId id, String destination) { + // ... } ``` -Sometimes the inferred type is not the type you want the variable to have. For -example, you may intend to assign values of other types later. In that case, -annotate the variable with the type you want. +With types, all of this is clarified. + -**GOOD:** -```dart -Widget build(BuildContext context) { - Widget result = Text('You won!'); - if (applyPadding) { - result = Padding(padding: EdgeInsets.all(8.0), child: result); - } - return result; -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1169.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1169.md index 5c0646ca..24073f48 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1169.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1169.md @@ -1,18 +1,61 @@ --- -title: "Use Flutter TODO format: // TODO(username): message, https://URL-to-issue." -verbose_name: "flutter_style_todos" +title: "Don't type annotate initializing formals" +verbose_name: "type_init_formals" category: "antipattern" weight: 70 severity: "major" --- -**DO** use Flutter TODO format. +From [Effective Dart](https://dart.dev/effective-dart/design#dont-type-annotate-initializing-formals): -From the [Flutter docs](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#comments): +**DON'T** type annotate initializing formals. -> TODOs should include the string TODO in all caps, followed by the GitHub username of the person with the best context about the problem referenced by the TODO in parenthesis. A TODO is not a commitment that the person referenced will fix the problem, it is intended to be the person with enough context to explain the problem. Thus, when you create a TODO, it is almost always your username that is given. +If a constructor parameter is using `this.x` to initialize a field, then the +type of the parameter is understood to be the same type as the field. If a +a constructor parameter is using `super.x` to forward to a super constructor, +then the type of the parameter is understood to be the same as the super +constructor parameter. + +Type annotating an initializing formal with a different type than that of the +field is OK. + +**BAD:** +```dart +class Point { + int x, y; + Point(int this.x, int this.y); +} +``` **GOOD:** ```dart -// TODO(username): message. -// TODO(username): message, https://URL-to-issue. +class Point { + int x, y; + Point(this.x, this.y); +} +``` + +**BAD:** +```dart +class A { + int a; + A(this.a); +} + +class B extends A { + B(int super.a); +} ``` + +**GOOD:** +```dart +class A { + int a; + A(this.a); +} + +class B extends A { + B(super.a); +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1170.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1170.md index 0f907cdf..8883fd89 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1170.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1170.md @@ -1,55 +1,49 @@ --- -title: "DO reference all public properties in debug methods." -verbose_name: "diagnostic_describe_all_properties" -category: "bug-risk" +title: "Don't use constant patterns with type literals" +verbose_name: "type_literal_in_constant_pattern" +category: "antipattern" weight: 70 severity: "major" --- -**DO** reference all public properties in `debug` method implementations. +If you meant to test if the object has type `Foo`, instead write `Foo _`. -Implementers of `Diagnosticable` should reference all public properties in -a `debugFillProperties(...)` or `debugDescribeChildren(...)` method -implementation to improve debuggability at runtime. - -Public properties are defined as fields and getters that are +**BAD:** +```dart +void f(Object? x) { + if (x case num) { + print('int or double'); + } +} +``` -* not package-private (e.g., prefixed with `_`) -* not `static` or overriding -* not themselves `Widget`s or collections of `Widget`s +**GOOD:** +```dart +void f(Object? x) { + if (x case num _) { + print('int or double'); + } +} +``` -In addition, the "debug" prefix is treated specially for properties in Flutter. -For the purposes of diagnostics, a property `foo` and a prefixed property -`debugFoo` are treated as effectively describing the same property and it is -sufficient to refer to one or the other. +If you do mean to test that the matched value (which you expect to have the +type `Type`) is equal to the type literal `Foo`, then this lint can be +silenced using `const (Foo)`. **BAD:** ```dart -class Absorber extends Widget { - bool get absorbing => _absorbing; - bool _absorbing; - bool get ignoringSemantics => _ignoringSemantics; - bool _ignoringSemantics; - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('absorbing', absorbing)); - // Missing reference to ignoringSemantics +void f(Object? x) { + if (x case int) { + print('int'); } } ``` **GOOD:** ```dart -class Absorber extends Widget { - bool get absorbing => _absorbing; - bool _absorbing; - bool get ignoringSemantics => _ignoringSemantics; - bool _ignoringSemantics; - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('absorbing', absorbing)); - properties.add(DiagnosticsProperty('ignoringSemantics', ignoringSemantics)); +void f(Object? x) { + if (x case const (int)) { + print('int'); } } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1171.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1171.md index 260443b0..a4cf5207 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1171.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1171.md @@ -1,34 +1,35 @@ --- -title: "Avoid relative imports for files in `lib/`." -verbose_name: "avoid_relative_lib_imports" -category: "bug-risk" +title: "`Future` results in `async` function bodies must be `await`ed or marked `unawaited` using `dart:async`" +verbose_name: "unawaited_futures" +category: "antipattern" weight: 70 severity: "major" --- -**DO** avoid relative imports for files in `lib/`. +**DO** await functions that return a `Future` inside of an async function body. -When mixing relative and absolute imports it's possible to create confusion -where the same member gets imported in two different ways. An easy way to avoid -that is to ensure you have no relative imports that include `lib/` in their -paths. +It's easy to forget await in async methods as naming conventions usually don't +tell us if a method is sync or async (except for some in `dart:io`). -You can also use 'always_use_package_imports' to disallow relative imports -between files within `lib/`. +When you really _do_ want to start a fire-and-forget `Future`, the recommended +way is to use `unawaited` from `dart:async`. The `// ignore` and +`// ignore_for_file` comments also work. **BAD:** ```dart -import 'package:foo/bar.dart'; - -import '../lib/baz.dart'; - -... +void main() async { + doSomething(); // Likely a bug. +} ``` **GOOD:** ```dart -import 'package:foo/bar.dart'; +Future doSomething() => ...; -import 'baz.dart'; +void main() async { + await doSomething(); -... + unawaited(doSomething()); // Explicitly-ignored fire-and-forget. +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1172.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1172.md index 16467560..dfe4fe83 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1172.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1172.md @@ -1,17 +1,30 @@ --- -title: "Do not use environment declared variables." -verbose_name: "do_not_use_environment" +title: "Unnecessary await keyword in return" +verbose_name: "unnecessary_await_in_return" category: "antipattern" weight: 70 severity: "major" --- -Using values derived from the environment at compile-time, creates -hidden global state and makes applications hard to understand and maintain. +Avoid returning an awaited expression when the expression type is assignable to +the function's return type. -**DON'T** use `fromEnvironment` or `hasEnvironment` factory constructors. **BAD:** ```dart -const loggingLevel = - bool.hasEnvironment('logging') ? String.fromEnvironment('logging') : null; +Future future; +Future f1() async => await future; +Future f2() async { + return await future; +} ``` + +**GOOD:** +```dart +Future future; +Future f1() => future; +Future f2() { + return future; +} +``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1173.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1173.md index a62d7174..3c27255e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1173.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1173.md @@ -1,38 +1,23 @@ --- -title: "Prefix library names with the package name and a dot-separated path." -verbose_name: "package_prefixed_library_names" +title: "Avoid using braces in interpolation when not needed" +verbose_name: "unnecessary_brace_in_string_interps" category: "antipattern" weight: 70 severity: "major" --- -**DO** prefix library names with the package name and a dot-separated path. +**AVOID** using braces in interpolation when not needed. -This guideline helps avoid the warnings you get when two libraries have the same -name. Here are the rules we recommend: +If you're just interpolating a simple identifier, and it's not immediately +followed by more alphanumeric text, the `{}` can and should be omitted. -* Prefix all library names with the package name. -* Make the entry library have the same name as the package. -* For all other libraries in a package, after the package name add the -dot-separated path to the library's Dart file. -* For libraries under `lib`, omit the top directory name. - -For example, say the package name is `my_package`. Here are the library names -for various files in the package: +**BAD:** +```dart +print("Hi, ${name}!"); +``` **GOOD:** ```dart -// In lib/my_package.dart -library my_package; - -// In lib/other.dart -library my_package.other; - -// In lib/foo/bar.dart -library my_package.foo.bar; +print("Hi, $name!"); +``` -// In example/foo/bar.dart -library my_package.example.foo.bar; -// In lib/src/private.dart -library my_package.src.private; -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1174.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1174.md index 66dd076f..a399cb61 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1174.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1174.md @@ -1,23 +1,55 @@ --- -title: "Avoid defining unused parameters in constructors." -verbose_name: "avoid_unused_constructor_parameters" +title: "Don't use explicit `break`s when a break is implied" +verbose_name: "unnecessary_breaks" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** defining unused parameters in constructors. +Only use a `break` in a non-empty switch case statement if you need to break +before the end of the case body. Dart does not support fallthrough execution +for non-empty cases, so `break`s at the end of non-empty switch case statements +are unnecessary. **BAD:** ```dart -class BadOne { - BadOne(int unusedParameter, [String unusedPositional]); +switch (1) { + case 1: + print("one"); + break; + case 2: + print("two"); + break; } +``` -class BadTwo { - int c; +**GOOD:** +```dart +switch (1) { + case 1: + print("one"); + case 2: + print("two"); +} +``` - BadTwo(int a, int b, int x) { - c = a + b; - } +```dart +switch (1) { + case 1: + case 2: + print("one or two"); } ``` + +```dart +switch (1) { + case 1: + break; + case 2: + print("just two"); +} +``` + +NOTE: This lint only reports unnecessary breaks in libraries with a +[language version](https://dart.dev/guides/language/evolution#language-versioning) +of 3.0 or greater. Explicit breaks are still required in Dart 2.19 and below. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1175.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1175.md index d138f4dc..4a87ac54 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1175.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1175.md @@ -1,229 +1,28 @@ --- -title: "Use case expressions that are valid in Dart 3.0." -verbose_name: "invalid_case_patterns" -category: "bug-risk" +title: "Avoid const keyword" +verbose_name: "unnecessary_const" +category: "antipattern" weight: 70 severity: "major" --- -Some case expressions that are valid in Dart 2.19 and below will become an error -or have changed semantics when a library is upgraded to 3.0. This lint flags -those expressions in order to ease migration to Dart 3.0. - -Some valid switch cases in 2.19 will become compile errors in Dart 3.0: - -* Set literals -* Parenthesized expressions -* Calls to `identical()`. -* Unary operator expressions `!`, `-`, or `~` (except for `-` before an integer - literal, which is a valid pattern and is fine) -* Binary operator expressions `!=`, `==`, `&`, `|`, `^`, `~/`, `>>`, `>>>`, - `<<`, `+`, `-`, `*`, `/`, `%`, `<`, `<=`, `>`, `>=`, `??`. -* Conditional operator `?:` -* `.length` calls on strings -* `is` and `is!` expressions - -Examples of all of them: - -```dart -switch (obj) { - case {1}: // Set literal. - case (1): // Parenthesized expression. - case identical(1, 2): // `identical()` call. - case -pi: // Unary operator. - case 1 + 2: // Binary operator. - case true ? 1 : 2: // Conditional operator. - case 'hi'.length: // .length call. - case i is int: // is expression. -} -``` - -Some valid switch cases in 2.19 are also syntactically valid patterns, but the -pattern matching behavior may be different from the current constant equality -behavior. They are: - -**List and map literals.** A list or map literal can appear as a constant in a -case: - -```dart -switch (obj) { - case [1, 2]: ... - case {'k': 'v'}: ... -} -``` - -Currently, the case will only match if the incoming value has the same identity -as the constant. So: - -```dart -test(List list) { - switch (list) { - case [1, 2]: print('Matched'); break; - default: print('Did not match'); break; - } -} - -main() { - test(const [1, 2]); // Prints "Matched". - test([1, 2]); // Prints "Did not match". -} -``` - -With patterns, a list or map literal becomes a list or map pattern. The pattern -destructures the incoming object and matches if the subpatterns all match. In -other words, list and map pattern match using something more like deep equality. - -With Dart 3.0, the above program prints "Matched" twice. - -**Constant constructor calls.** Similar to collections, you can construct a -constant instance of a class in a case: - -```dart -class Point { - final int x; - final int y; - const Point({this.x, this.y}); -} - -test(Point p) { - switch (p) { - case Point(x: 1, y: 2): print('Matched'); break; - default: print('Did not match'); break; - } -} - -main() { - test(const Point(1, 2)); // Prints "Matched". - test(Point(1, 2)); // Prints "Did not match". -} -``` - -Again, like collections, the case currently only matches if the incoming value -has the same identity. With patterns, the `Point(...)` syntax becomes an object -pattern that destructures the incoming point, calls the `x` and `y` getters on -it and then matches the results of those against the corresponding subpatterns. - -In this example, it will print "Matched" twice. - -Note that object patterns only support named fields. So any constant constructor -in a case today that has positional arguments will become a compile-time error -when parsed as a pattern. A constant constructor call with no arguments is a -valid object pattern and only does a type test: - -```dart -class Thing { - const Thing(); -} - -test(Thing t) { - switch (t) { - case Thing(): print('Matched'); break; - default: print('Did not match'); break; - } -} - -main() { - test(const Thing()); // Prints "Matched". - test(Thing()); // Prints "Did not match". -} -``` - -When interpreted as a pattern, this prints "Matched" twice. - -**Wildcards.** Today, you can have a constant named `_`: - -```dart -test(int n) { - const _ = 3; - switch (n) { - case _: print('Matched'); break; - default: print('Did not match'); break; - } -} - -main() { - test(3); // Prints "Matched". - test(5); // Prints "Did not match". -} -``` - -With patterns, the identifier `_` is treated as a pattern that matches all -values, so this prints "Matched" twice. - -**Logic operators.** The logic operators `&&` and `||` are valid constant -expressions and also valid patterns. As a constant expression, they simply -evaluate the expression to a boolean and match if the incoming value is equal to -that boolean value. So: - -```dart -test(bool b) { - switch (b) { - case true && false: print('Matched'); break; - default: print('Did not match'); break; - } -} - -main() { - test(false); // Prints "Matched". - test(true); // Prints "Did not match". -} -``` - -With Dart 3.0, these become patterns. The above example prints "Did not match" -twice because no boolean value can be both true and false. - -Many of invalid cases can be mechanically changed to something that is valid -both in Dart today and valid and means the same in Dart 3.0. - -**Parenthesized expressions:** Provided the inner expression is one that's not -broken in Dart 3.0, just discard the parentheses. - -**List literals, map literals, set literals, and constant constructor calls:** -Put `const` before the literal or call. This turns it into a constant pattern -which preserves the current behavior: +**AVOID** repeating const keyword in a const context. **BAD:** - ```dart -case [1, 2]: -case {'k': 'v'}: -case {1, 2}: -case Point(1, 2): +class A { const A(); } +m(){ + const a = const A(); + final b = const [const A()]; +} ``` **GOOD:** - ```dart -case const [1, 2]: -case const {'k': 'v'}: -case const {1, 2}: -case const Point(1, 2): -``` - -* **Wildcards:** Rename the constant from `_` to something else. Since the name -is private, this can be done locally in the library without affecting other -code. - -* **Everything else:** For any other invalid expression, you have to hoist the -expression out into a new named constant. For example, if you have code like -this: - - -**BAD:** - -```dart -switch (n) { - case 1 + 2: ... +class A { const A(); } +m(){ + const a = A(); + final b = const [A()]; } ``` -It can be fixed by changing it to: -**GOOD:** - - ```dart -const three = 1 + 2; - -switch (n) { - case three: ... -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1176.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1176.md index a91ad23b..2f2b2c9f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1176.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1176.md @@ -1,34 +1,34 @@ --- -title: "Unnecessary parentheses can be removed." -verbose_name: "unnecessary_parenthesis" +title: "Unnecessary `.new` constructor name" +verbose_name: "unnecessary_constructor_name" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** using parentheses when not needed. +**PREFER** using the default unnamed Constructor over `.new`. + +Given a class `C`, the named unnamed constructor `C.new` refers to the same +constructor as the unnamed `C`. As such it adds nothing but visual noise to +invocations and should be avoided (unless being used to identify a constructor +tear-off). **BAD:** ```dart -a = (b); +class A { + A.new(); // LINT +} + +var a = A.new(); // LINT ``` **GOOD:** ```dart -a = b; -``` +class A { + A.ok(); +} -Parentheses are considered unnecessary if they do not change the meaning of the -code and they do not improve the readability of the code. The goal is not to -force all developers to maintain the expression precedence table in their heads, -which is why the second condition is included. Examples of this condition -include: +var a = A(); +var aa = A.ok(); +var makeA = A.new; +``` -* cascade expressions - it is sometimes not clear what the target of a cascade - expression is, especially with assignments, or nested cascades. For example, - the expression `a.b = (c..d)`. -* expressions with whitespace between tokens - it can look very strange to see - an expression like `!await foo` which is valid and equivalent to - `!(await foo)`. -* logical expressions - parentheses can improve the readability of the implicit - grouping defined by precedence. For example, the expression - `(a && b) || c && d`. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1177.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1177.md index 2cc1a53f..0f156b15 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1177.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1177.md @@ -1,53 +1,36 @@ --- -title: "Avoid overloading operator == and hashCode on classes not marked `@immutable`." -verbose_name: "avoid_equals_and_hash_code_on_mutable_classes" +title: "Don't use `final` for local variables" +verbose_name: "unnecessary_final" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/design#avoid-defining-custom-equality-for-mutable-classes): +Use `var`, not `final`, when declaring local variables. -**AVOID** overloading operator == and hashCode on classes not marked `@immutable`. +Per [Effective Dart](https://dart.dev/effective-dart/usage#do-follow-a-consistent-rule-for-var-and-final-on-local-variables), +there are two styles in wide use. This rule enforces the `var` style. +For the alternative style that prefers `final`, enable `prefer_final_locals` +and `prefer_final_in_for_each` instead. -If a class is not immutable, overloading `operator ==` and `hashCode` can -lead to unpredictable and undesirable behavior when used in collections. +For fields, `final` is always recommended; see the rule `prefer_final_fields`. **BAD:** ```dart -class B { - String key; - const B(this.key); - @override - operator ==(other) => other is B && other.key == key; - @override - int get hashCode => key.hashCode; +void badMethod() { + final label = 'Final or var?'; + for (final char in ['v', 'a', 'r']) { + print(char); + } } ``` **GOOD:** ```dart -@immutable -class A { - final String key; - const A(this.key); - @override - operator ==(other) => other is A && other.key == key; - @override - int get hashCode => key.hashCode; +void goodMethod() { + var label = 'Final or var?'; + for (var char in ['v', 'a', 'r']) { + print(char); + } } ``` -NOTE: The lint checks the use of the `@immutable` annotation, and will trigger -even if the class is otherwise not mutable. Thus: - -**BAD:** -```dart -class C { - final String key; - const C(this.key); - @override - operator ==(other) => other is C && other.key == key; - @override - int get hashCode => key.hashCode; -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1178.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1178.md index df48e9ad..a4ba9ea0 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1178.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1178.md @@ -1,52 +1,41 @@ --- -title: "Don't put any logic in createState." -verbose_name: "no_logic_in_create_state" -category: "bug-risk" +title: "Avoid wrapping fields in getters and setters just to be "safe"" +verbose_name: "unnecessary_getters_setters" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** put any logic in `createState()`. +From [Effective Dart](https://dart.dev/effective-dart/usage#dont-wrap-a-field-in-a-getter-and-setter-unnecessarily): -Implementations of `createState()` should return a new instance -of a State object and do nothing more. Since state access is preferred -via the `widget` field, passing data to `State` objects using custom -constructor parameters should also be avoided and so further, the State -constructor is required to be passed no arguments. +**AVOID** wrapping fields in getters and setters just to be "safe". -**BAD:** -```dart -MyState global; +In Java and C#, it's common to hide all fields behind getters and setters (or +properties in C#), even if the implementation just forwards to the field. That +way, if you ever need to do more work in those members, you can do it without needing +to touch the callsites. This is because calling a getter method is different +than accessing a field in Java, and accessing a property isn't binary-compatible +with accessing a raw field in C#. -class MyStateful extends StatefulWidget { - @override - MyState createState() { - global = MyState(); - return global; - } -} -``` +Dart doesn't have this limitation. Fields and getters/setters are completely +indistinguishable. You can expose a field in a class and later wrap it in a +getter and setter without having to touch any code that uses that field. +**BAD:** ```dart -class MyStateful extends StatefulWidget { - @override - MyState createState() => MyState()..field = 42; +class Box { + var _contents; + get contents => _contents; + set contents(value) { + _contents = value; + } } ``` +**GOOD:** ```dart -class MyStateful extends StatefulWidget { - @override - MyState createState() => MyState(42); +class Box { + var contents; } ``` -**GOOD:** -```dart -class MyStateful extends StatefulWidget { - @override - MyState createState() { - return MyState(); - } -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1179.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1179.md index 68e34f68..0ad0384b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1179.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1179.md @@ -1,26 +1,22 @@ --- -title: "Prefer int literals over double literals." -verbose_name: "prefer_int_literals" +title: "Don't create a lambda when a tear-off will do" +verbose_name: "unnecessary_lambdas" category: "antipattern" weight: 70 severity: "major" --- -**DO** use int literals rather than the corresponding double literal. +**DON'T** create a lambda when a tear-off will do. **BAD:** ```dart -const double myDouble = 8.0; -final anotherDouble = myDouble + 7.0e2; -main() { - someMethod(6.0); -} +names.forEach((name) { + print(name); +}); ``` **GOOD:** ```dart -const double myDouble = 8; -final anotherDouble = myDouble + 700; -main() { - someMethod(6); -} +names.forEach(print); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1180.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1180.md index beb8b308..65b1b214 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1180.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1180.md @@ -1,21 +1,37 @@ --- -title: "Avoid leading underscores for library prefixes." -verbose_name: "no_leading_underscores_for_library_prefixes" +title: "Don't specify the `late` modifier when it is not needed" +verbose_name: "unnecessary_late" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use a leading underscore for library prefixes. -There is no concept of "private" for library prefixes. When one of those has a -name that starts with an underscore, it sends a confusing signal to the reader. -To avoid that, don't use leading underscores in those names. +**DO** not specify the `late` modifier for top-level and static variables +when the declaration contains an initializer. + +Top-level and static variables with initializers are already evaluated lazily +as if they are marked `late`. + +**BAD:** +```dart +late String badTopLevel = ''; +``` + +**GOOD:** +```dart +String goodTopLevel = ''; +``` **BAD:** ```dart -import 'dart:core' as _core; +class BadExample { + static late String badStatic = ''; +} ``` **GOOD:** ```dart -import 'dart:core' as core; +class GoodExample { + late String goodStatic; +} ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1181.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1181.md index cf49ce82..c57afa99 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1181.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1181.md @@ -1,27 +1,29 @@ --- -title: "Prefer using /// for doc comments." -verbose_name: "slash_for_doc_comments" +title: "Avoid library directives unless they have documentation comments or annotations" +verbose_name: "unnecessary_library_directive" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/documentation#do-use--doc-comments-to-document-members-and-types): +**DO** use library directives if you want to document a library and/or annotate +a library. -**DO** use `///` for documentation comments. - -Although Dart supports two syntaxes of doc comments (`///` and `/**`), we -prefer using `///` for doc comments. +**BAD:** +```dart +library; +``` **GOOD:** ```dart -/// Parses a set of option strings. For each option: -/// -/// * If it is `null`, then it is ignored. -/// * If it is a string, then [validate] is called on it. -/// * If it is any other type, it is *not* validated. -void parse(List options) { - // ... -} +/// This library does important things +library; ``` -Within a doc comment, you can use markdown for formatting. +```dart +@TestOn('js') +library; +``` + +NOTE: Due to limitations with this lint, libraries with parts will not be +flagged for unnecessary library directives. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1182.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1182.md index 75630b2c..7e7793a1 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1182.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1182.md @@ -1,31 +1,26 @@ --- -title: "Use `ColoredBox`." -verbose_name: "use_colored_box" +title: "Unnecessary new keyword" +verbose_name: "unnecessary_new" category: "antipattern" weight: 70 severity: "major" --- -**DO** use `ColoredBox` when `Container` has only a `Color`. - -A `Container` is a heavier Widget than a `ColoredBox`, and as bonus, -`ColoredBox` has a `const` constructor. +**AVOID** new keyword to create instances. **BAD:** ```dart -Widget buildArea() { - return Container( - color: Colors.blue, - child: const Text('hello'), - ); +class A { A(); } +m(){ + final a = new A(); } ``` **GOOD:** ```dart -Widget buildArea() { - return const ColoredBox( - color: Colors.blue, - child: Text('hello'), - ); +class A { A(); } +m(){ + final a = A(); } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1183.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1183.md index 71bd9314..d2da6633 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1183.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1183.md @@ -1,53 +1,25 @@ --- -title: "Use `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors" -verbose_name: "sized_box_shrink_expand" +title: "Avoid null in null-aware assignment" +verbose_name: "unnecessary_null_aware_assignments" category: "antipattern" weight: 70 severity: "major" --- -Use `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors -appropriately. +**AVOID** `null` in null-aware assignment. -Either the `SizedBox.shrink(...)` or `SizedBox.expand(...)` constructor should -be used instead of the more general `SizedBox(...)` constructor when one of the -named constructors capture the intent of the code more succinctly. - -**Examples** +Using `null` on the right-hand side of a null-aware assignment effectively makes +the assignment redundant. **BAD:** ```dart -Widget buildLogo() { - return SizedBox( - height: 0, - width: 0, - child: const MyLogo(), - ); -} -``` - -```dart -Widget buildLogo() { - return SizedBox( - height: double.infinity, - width: double.infinity, - child: const MyLogo(), - ); -} +var x; +x ??= null; ``` **GOOD:** ```dart -Widget buildLogo() { - return SizedBox.shrink( - child: const MyLogo(), - ); -} +var x; +x ??= 1; ``` -```dart -Widget buildLogo() { - return SizedBox.expand( - child: const MyLogo(), - ); -} -``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1184.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1184.md index 75e16d99..705ea30b 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1184.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1184.md @@ -1,29 +1,28 @@ --- -title: "Avoid returning null from members whose return type is bool, double, int, r' or num." -verbose_name: "avoid_returning_null" +title: "Unnecessary null aware operator on extension on a nullable type" +verbose_name: "unnecessary_null_aware_operator_on_extension_on_nullable" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** returning null from members whose return type is bool, double, int, -or num. - -Functions that return primitive types such as bool, double, int, and num are -generally expected to return non-nullable values. Thus, returning null where a -primitive type was expected can lead to runtime exceptions. +Avoid null aware operators for members defined in an extension on a nullable type. **BAD:** + ```dart -bool getBool() => null; -num getNum() => null; -int getInt() => null; -double getDouble() => null; +extension E on int? { + int m() => 1; +} +f(int? i) => i?.m(); ``` **GOOD:** + ```dart -bool getBool() => false; -num getNum() => -1; -int getInt() => -1; -double getDouble() => -1.0; +extension E on int? { + int m() => 1; +} +f(int? i) => i.m(); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1185.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1185.md index afb67856..db689d66 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1185.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1185.md @@ -1,80 +1,24 @@ --- -title: "Don't implement classes that override `==`." -verbose_name: "avoid_implementing_value_types" +title: "Avoid using `null` in `if null` operators" +verbose_name: "unnecessary_null_in_if_null_operators" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** implement classes that override `==`. +**AVOID** using `null` as an operand in `if null` operators. -The `==` operator is contractually required to be an equivalence relation; -that is, symmetrically for all objects `o1` and `o2`, `o1 == o2` and `o2 == o1` -must either both be true, or both be false. - -> _NOTE_: Dart does not have true _value types_, so instead we consider a class -> that implements `==` as a _proxy_ for identifying value types. - -When using `implements`, you do not inherit the method body of `==`, making it -nearly impossible to follow the contract of `==`. Classes that override `==` -typically are usable directly in tests _without_ creating mocks or fakes as -well. For example, for a given class `Size`: - -```dart -class Size { - final int inBytes; - const Size(this.inBytes); - - @override - bool operator ==(Object other) => other is Size && other.inBytes == inBytes; - - @override - int get hashCode => inBytes.hashCode; -} -``` +Using `null` in an `if null` operator is redundant, regardless of which side +`null` is used on. **BAD:** ```dart -class CustomSize implements Size { - final int inBytes; - const CustomSize(this.inBytes); - - int get inKilobytes => inBytes ~/ 1000; -} -``` - -**BAD:** -```dart -import 'package:test/test.dart'; -import 'size.dart'; - -class FakeSize implements Size { - int inBytes = 0; -} - -void main() { - test('should not throw on a size >1Kb', () { - expect(() => someFunction(FakeSize()..inBytes = 1001), returnsNormally); - }); -} +var x = a ?? null; +var y = null ?? 1; ``` **GOOD:** ```dart -class ExtendedSize extends Size { - ExtendedSize(int inBytes) : super(inBytes); - - int get inKilobytes => inBytes ~/ 1000; -} +var x = a ?? 1; ``` -**GOOD:**: -```dart -import 'package:test/test.dart'; -import 'size.dart'; -void main() { - test('should not throw on a size >1Kb', () { - expect(() => someFunction(Size(1001)), returnsNormally); - }); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1186.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1186.md index a275437c..c8b7ac19 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1186.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1186.md @@ -1,78 +1,21 @@ --- -title: "Use initializing formals when possible." -verbose_name: "prefer_initializing_formals" +title: "Use a non-nullable type for a final variable initialized with a non-nullable value" +verbose_name: "unnecessary_nullable_for_final_variable_declarations" category: "antipattern" weight: 70 severity: "major" --- -**DO** use initializing formals when possible. - -Using initializing formals when possible makes your code more terse. +Use a non-nullable type for a final variable initialized with a non-nullable +value. **BAD:** ```dart -class Point { - num x, y; - Point(num x, num y) { - this.x = x; - this.y = y; - } -} +final int? i = 1; ``` **GOOD:** ```dart -class Point { - num x, y; - Point(this.x, this.y); -} -``` - -**BAD:** -```dart -class Point { - num x, y; - Point({num x, num y}) { - this.x = x; - this.y = y; - } -} +final int i = 1; ``` -**GOOD:** -```dart -class Point { - num x, y; - Point({this.x, this.y}); -} -``` -**NOTE:** -This rule will not generate a lint for named parameters unless the parameter -name and the field name are the same. The reason for this is that resolving -such a lint would require either renaming the field or renaming the parameter, -and both of those actions would potentially be a breaking change. For example, -the following will not generate a lint: - -```dart -class Point { - bool isEnabled; - Point({bool enabled}) { - this.isEnabled = enabled; // OK - } -} -``` - -**NOTE:** -Also note that it is possible to enforce a type that is stricter than the -initialized field with an initializing formal parameter. In the following -example the unnamed `Bid` constructor requires a non-null `int` despite -`amount` being declared nullable (`int?`). - -```dart -class Bid { - final int? amount; - Bid(int this.amount); - Bid.pass() : amount = null; -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1187.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1187.md index 659fbd67..61c5ee9e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1187.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1187.md @@ -1,48 +1,41 @@ --- -title: "Don't use constant patterns with type literals." -verbose_name: "type_literal_in_constant_pattern" +title: "Don't override a method to do a super method invocation with the same parameters" +verbose_name: "unnecessary_overrides" category: "antipattern" weight: 70 severity: "major" --- -If you meant to test if the object has type `Foo`, instead write `Foo _`. +**DON'T** override a method to do a super method invocation with same parameters. **BAD:** ```dart -void f(Object? x) { - if (x case num) { - print('int or double'); +class A extends B { + @override + void foo() { + super.foo(); } } ``` **GOOD:** ```dart -void f(Object? x) { - if (x case num _) { - print('int or double'); +class A extends B { + @override + void foo() { + doSomethingElse(); } } ``` -If you do mean to test that the matched value (which you expect to have the -type `Type`) is equal to the type literal `Foo`, then this lint can be -silenced using `const (Foo)`. +It's valid to override a member in the following cases: + +* if a type (return type or a parameter type) is not the exactly the same as the + super member, +* if the `covariant` keyword is added to one of the parameters, +* if documentation comments are present on the member, +* if the member has annotations other than `@override`, +* if the member is not annotated with `@protected`, and the super member is. + +`noSuchMethod` is a special method and is not checked by this rule. -**BAD:** -```dart -void f(Object? x) { - if (x case int) { - print('int'); - } -} -``` -**GOOD:** -```dart -void f(Object? x) { - if (x case const (int)) { - print('int'); - } -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1188.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1188.md index bf6e2530..53288e4d 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1188.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1188.md @@ -1,59 +1,35 @@ --- -title: "Don't type annotate initializing formals." -verbose_name: "type_init_formals" +title: "Unnecessary parentheses can be removed" +verbose_name: "unnecessary_parenthesis" category: "antipattern" weight: 70 severity: "major" --- -From [Effective Dart](https://dart.dev/effective-dart/design#dont-type-annotate-initializing-formals): - -**DON'T** type annotate initializing formals. - -If a constructor parameter is using `this.x` to initialize a field, then the -type of the parameter is understood to be the same type as the field. If a -a constructor parameter is using `super.x` to forward to a super constructor, -then the type of the parameter is understood to be the same as the super -constructor parameter. - -Type annotating an initializing formal with a different type than that of the -field is OK. +**AVOID** using parentheses when not needed. **BAD:** ```dart -class Point { - int x, y; - Point(int this.x, int this.y); -} +a = (b); ``` **GOOD:** ```dart -class Point { - int x, y; - Point(this.x, this.y); -} +a = b; ``` -**BAD:** -```dart -class A { - int a; - A(this.a); -} +Parentheses are considered unnecessary if they do not change the meaning of the +code and they do not improve the readability of the code. The goal is not to +force all developers to maintain the expression precedence table in their heads, +which is why the second condition is included. Examples of this condition +include: + +* cascade expressions - it is sometimes not clear what the target of a cascade + expression is, especially with assignments, or nested cascades. For example, + the expression `a.b = (c..d)`. +* expressions with whitespace between tokens - it can look very strange to see + an expression like `!await foo` which is valid and equivalent to + `!(await foo)`. +* logical expressions - parentheses can improve the readability of the implicit + grouping defined by precedence. For example, the expression + `(a && b) || c && d`. -class B extends A { - B(int super.a); -} -``` - -**GOOD:** -```dart -class A { - int a; - A(this.a); -} - -class B extends A { - B(super.a); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1189.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1189.md index bbc64eb7..d8640b16 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1189.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1189.md @@ -1,24 +1,22 @@ --- -title: "Unnecessary new keyword." -verbose_name: "unnecessary_new" +title: "Unnecessary raw string" +verbose_name: "unnecessary_raw_strings" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** new keyword to create instances. +Use raw string only when needed. **BAD:** ```dart -class A { A(); } -m(){ - final a = new A(); -} +var s1 = r'a'; ``` **GOOD:** ```dart -class A { A(); } -m(){ - final a = A(); -} +var s1 = 'a'; +var s2 = r'$a'; +var s3 = r'\a'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1190.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1190.md index 4f571e97..98cbcbe6 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1190.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1190.md @@ -1,27 +1,22 @@ --- -title: "Name libraries using `lowercase_with_underscores`." -verbose_name: "library_names" +title: "Remove unnecessary backslashes in strings" +verbose_name: "unnecessary_string_escapes" category: "antipattern" weight: 70 severity: "major" --- -**DO** name libraries using `lowercase_with_underscores`. - -Some file systems are not case-sensitive, so many projects require filenames to -be all lowercase. Using a separating character allows names to still be readable -in that form. Using underscores as the separator ensures that the name is still -a valid Dart identifier, which may be helpful if the language later supports -symbolic imports. +Remove unnecessary backslashes in strings. **BAD:** ```dart -library peg-parser; +'this string contains 2 \"double quotes\" '; +"this string contains 2 \'single quotes\' "; ``` **GOOD:** ```dart -library peg_parser; +'this string contains 2 "double quotes" '; +"this string contains 2 'single quotes' "; ``` -The lint `file_names` can be used to enforce the same kind of naming on the -file. + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1191.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1191.md index b3d451b4..86b76699 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1191.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1191.md @@ -1,20 +1,22 @@ --- -title: "Prefer intValue.isOdd/isEven instead of checking the result of % 2." -verbose_name: "use_is_even_rather_than_modulo" +title: "Unnecessary string interpolation" +verbose_name: "unnecessary_string_interpolations" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** the use of intValue.isOdd/isEven to check for evenness. +**DON'T** use string interpolation if there's only a string expression in it. **BAD:** ```dart -bool isEven = 1 % 2 == 0; -bool isOdd = 13 % 2 == 1; +String message; +String o = '$message'; ``` **GOOD:** ```dart -bool isEven = 1.isEven; -bool isOdd = 13.isOdd; +String message; +String o = message; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1192.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1192.md index 4a549326..11617d2f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1192.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1192.md @@ -1,32 +1,42 @@ --- -title: "Avoid redundant argument values." -verbose_name: "avoid_redundant_argument_values" +title: "Don't access members with `this` unless avoiding shadowing" +verbose_name: "unnecessary_this" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** pass an argument that matches the corresponding parameter's default -value. +From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-this-when-not-needed-to-avoid-shadowing): + +**DON'T** use `this` when not needed to avoid shadowing. **BAD:** ```dart -void f({bool valWithDefault = true, bool? val}) { - ... -} - -void main() { - f(valWithDefault: true); +class Box { + int value; + void update(int newValue) { + this.value = newValue; + } } ``` **GOOD:** ```dart -void f({bool valWithDefault = true, bool? val}) { - ... +class Box { + int value; + void update(int newValue) { + value = newValue; + } } +``` -void main() { - f(valWithDefault: false); - f(); +**GOOD:** +```dart +class Box { + int value; + void update(int value) { + this.value = value; + } } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1193.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1193.md index 7ba78a47..ff51524e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1193.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1193.md @@ -1,28 +1,24 @@ --- -title: "Start multiline strings with a newline." -verbose_name: "leading_newlines_in_multiline_strings" +title: "Unnecessary toList() in spreads" +verbose_name: "unnecessary_to_list_in_spreads" category: "antipattern" weight: 70 severity: "major" --- -Multiline strings are easier to read when they start with a newline (a newline -starting a multiline string is ignored). +Unnecessary `toList()` in spreads. **BAD:** ```dart -var s1 = '''{ - "a": 1, - "b": 2 -}'''; +children: [ + ...['foo', 'bar', 'baz'].map((String s) => Text(s)).toList(), +] ``` **GOOD:** ```dart -var s1 = ''' -{ - "a": 1, - "b": 2 -}'''; - -var s2 = '''This one-liner multiline string is ok. It usually allows to escape both ' and " in the string.'''; +children: [ + ...['foo', 'bar', 'baz'].map((String s) => Text(s)), +] ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1194.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1194.md index e8332146..08f87b9e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1194.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1194.md @@ -1,41 +1,33 @@ --- -title: "Avoid leading underscores for local identifiers." -verbose_name: "no_leading_underscores_for_local_identifiers" +title: "Unreachable top-level members in executable libraries" +verbose_name: "unreachable_from_main" category: "antipattern" weight: 70 severity: "major" --- -**DON'T** use a leading underscore for identifiers that aren't private. Dart -uses a leading underscore in an identifier to mark members and top-level -declarations as private. This trains users to associate a leading underscore -with one of those kinds of declarations. They see `_` and think "private". -There is no concept of "private" for local variables or parameters. When one of -those has a name that starts with an underscore, it sends a confusing signal to -the reader. To avoid that, don't use leading underscores in those names. +Any member declared in an executable library should be used directly inside that +library. An executable library is a library that contains a `main` top-level +function or that contains a top-level function annotated with +`@pragma('vm:entry-point')`). Executable libraries are not usually imported +and it's better to avoid defining unused members. -**EXCEPTION:**: An unused parameter can be named `_`, `__`, `___`, etc. This is -common practice in callbacks where you are passed a value but you don't need -to use it. Giving it a name that consists solely of underscores is the idiomatic -way to indicate that the value isn't used. +This rule assumes that an executable library isn't imported by other libraries +except to execute its `main` function. **BAD:** + ```dart -void print(String _name) { - var _size = _name.length; - ... -} +main() {} +void f() {} ``` + **GOOD:** ```dart -void print(String name) { - var size = name.length; - ... +main() { + f(); } +void f() {} ``` -**OK:** -```dart -[1,2,3].map((_) => print('Hello')); -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1195.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1195.md index 2ff6ccbb..40148099 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1195.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1195.md @@ -1,85 +1,32 @@ --- -title: "Boolean expression composed only with literals." -verbose_name: "literal_only_boolean_expressions" -category: "bug-risk" +title: "Use `ColoredBox`" +verbose_name: "use_colored_box" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** test for conditions composed only by literals, since the value can be -inferred at compile time. +**DO** use `ColoredBox` when `Container` has only a `Color`. -Conditional statements using a condition which cannot be anything but FALSE have -the effect of making blocks of code non-functional. If the condition cannot -evaluate to anything but `true`, the conditional statement is completely -redundant, and makes the code less readable. -It is quite likely that the code does not match the programmer's intent. -Either the condition should be removed or it should be updated so that it does -not always evaluate to `true` or `false`. +A `Container` is a heavier Widget than a `ColoredBox`, and as bonus, +`ColoredBox` has a `const` constructor. **BAD:** ```dart -void bad() { - if (true) {} // LINT +Widget buildArea() { + return Container( + color: Colors.blue, + child: const Text('hello'), + ); } ``` -**BAD:** -```dart -void bad() { - if (true && 1 != 0) {} // LINT -} -``` - -**BAD:** -```dart -void bad() { - if (1 != 0 && true) {} // LINT -} -``` - -**BAD:** -```dart -void bad() { - if (1 < 0 && true) {} // LINT -} -``` - -**BAD:** -```dart -void bad() { - if (true && false) {} // LINT -} -``` - -**BAD:** -```dart -void bad() { - if (1 != 0) {} // LINT -} -``` - -**BAD:** -```dart -void bad() { - if (true && 1 != 0 || 3 < 4) {} // LINT -} -``` - -**BAD:** -```dart -void bad() { - if (1 != 0 || 3 < 4 && true) {} // LINT -} -``` - -**NOTE:** that an exception is made for the common `while (true) { }` idiom, -which is often reasonably preferred to the equivalent `for (;;)`. - **GOOD:** ```dart -void good() { - while (true) { - // Do stuff. - } +Widget buildArea() { + return const ColoredBox( + color: Colors.blue, + child: Text('hello'), + ); } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1196.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1196.md index 1d7fffa1..df5cadfc 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1196.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1196.md @@ -1,29 +1,42 @@ --- -title: "Use a function declaration to bind a function to a name." -verbose_name: "prefer_function_declarations_over_variables" +title: "Use `DecoratedBox`" +verbose_name: "use_decorated_box" category: "antipattern" weight: 70 severity: "major" --- -**DO** use a function declaration to bind a function to a name. +**DO** use `DecoratedBox` when `Container` has only a `Decoration`. -As Dart allows local function declarations, it is a good practice to use them in -the place of function literals. +A `Container` is a heavier Widget than a `DecoratedBox`, and as bonus, +`DecoratedBox` has a `const` constructor. **BAD:** ```dart -void main() { - var localFunction = () { - ... - }; +Widget buildArea() { + return Container( + decoration: const BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.all( + Radius.circular(5), + ), + ), + child: const Text('...'), + ); } ``` **GOOD:** ```dart -void main() { - localFunction() { - ... - } +Widget buildArea() { + return const DecoratedBox( + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.all( + Radius.circular(5), + ), + ), + child: Text('...'), + ); } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1197.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1197.md index 9808aba5..05e3d6c5 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1197.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1197.md @@ -1,24 +1,53 @@ --- -title: "Use key in widget constructors." -verbose_name: "use_key_in_widget_constructors" -category: "bug-risk" +title: "Use enums rather than classes that behave like enums" +verbose_name: "use_enums" +category: "antipattern" weight: 70 severity: "major" --- -**DO** use key in widget constructors. +Classes that look like enumerations should be declared as `enum`s. -It's a good practice to expose the ability to provide a key when creating public -widgets. +**DO** use enums where appropriate. + +Candidates for enums are classes that: + + * are concrete, + * are private or have only private generative constructors, + * have two or more static const fields with the same type as the class, + * have generative constructors that are only invoked at the top-level of the + initialization expression of these static fields, + * do not define `hashCode`, `==`, `values` or `index`, + * do not extend any class other than `Object`, and + * have no subclasses declared in the defining library. + +To learn more about creating and using these enums, check out +[Declaring enhanced enums](https://dart.dev/language/enums#declaring-enhanced-enums). **BAD:** ```dart -class MyPublicWidget extends StatelessWidget { +class LogPriority { + static const error = LogPriority._(1, 'Error'); + static const warning = LogPriority._(2, 'Warning'); + static const log = LogPriority._unknown('Log'); + + final String prefix; + final int priority; + const LogPriority._(this.priority, this.prefix); + const LogPriority._unknown(String prefix) : this._(-1, prefix); } ``` **GOOD:** ```dart -class MyPublicWidget extends StatelessWidget { - MyPublicWidget({super.key}); +enum LogPriority { + error(1, 'Error'), + warning(2, 'Warning'), + log.unknown('Log'); + + final String prefix; + final int priority; + const LogPriority(this.priority, this.prefix); + const LogPriority.unknown(String prefix) : this(-1, prefix); } ``` + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1198.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1198.md index cbb2b9de..e8ce261c 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1198.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1198.md @@ -1,27 +1,23 @@ --- -title: "Prefer const literals as parameters of constructors on @immutable classes." -verbose_name: "prefer_const_literals_to_create_immutables" +title: "Prefer an 8-digit hexadecimal integer(0xFFFFFFFF) to instantiate Color" +verbose_name: "use_full_hex_values_for_flutter_colors" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** using `const` for instantiating list, map and set literals used as -parameters in immutable class instantiations. +**PREFER** an 8-digit hexadecimal integer(0xFFFFFFFF) to instantiate Color. Colors +have four 8-bit channels, which adds up to 32 bits, so Colors are described +using a 32 bit integer. **BAD:** ```dart -@immutable -class A { - A(this.v); - final v; -} - -A a1 = new A([1]); -A a2 = new A({}); +Color(1); +Color(0x000001); ``` **GOOD:** ```dart -A a1 = new A(const [1]); -A a2 = new A(const {}); +Color(0x00000001); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1199.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1199.md index 3899a5b1..254b8e59 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1199.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1199.md @@ -1,41 +1,20 @@ --- -title: "Don't implicitly reopen classes." -verbose_name: "implicit_reopen" -category: "bug-risk" +title: "Use generic function type syntax for parameters" +verbose_name: "use_function_type_syntax_for_parameters" +category: "antipattern" weight: 70 severity: "major" --- -Using an `interface`, `base`, `final`, or `sealed` modifier on a class, -or a `base` modifier on a mixin, -authors can control whether classes and mixins allow being implemented, -extended, and/or mixed in from outside of the library where they're defined. -In some cases, it's possible for an author to inadvertently relax these controls -and implicitly "reopen" a class. (A similar reopening cannot occur with a mixin.) - -This lint guards against unintentionally reopening a class by requiring such -cases to be made explicit with the -[`@reopen`](https://pub.dev/documentation/meta/latest/meta/reopen-constant.html) -annotation in `package:meta`. +Use generic function type syntax for parameters. **BAD:** ```dart -interface class I {} - -class C extends I {} // LINT +Iterable where(bool predicate(T element)) {} ``` **GOOD:** ```dart -interface class I {} - -final class C extends I {} +Iterable where(bool Function(T) predicate) {} ``` -```dart -import 'package:meta/meta.dart'; - -interface class I {} -@reopen -class C extends I {} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1200.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1200.md index 03e6e3ad..55f74227 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1200.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1200.md @@ -1,26 +1,28 @@ --- -title: "Avoid JavaScript rounded ints." -verbose_name: "avoid_js_rounded_ints" +title: "Use if-null operators to convert nulls to bools" +verbose_name: "use_if_null_to_convert_nulls_to_bools" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** integer literals that cannot be represented exactly when compiled to -JavaScript. +From [Effective Dart](https://dart.dev/effective-dart/usage#prefer-using--to-convert-null-to-a-boolean-value): -When a program is compiled to JavaScript `int` and `double` become JavaScript -Numbers. Too large integers (`value < Number.MIN_SAFE_INTEGER` or -`value > Number.MAX_SAFE_INTEGER`) may be rounded to the closest Number value. - -For instance `1000000000000000001` cannot be represented exactly as a JavaScript -Number, so `1000000000000000000` will be used instead. +Use if-null operators to convert nulls to bools. **BAD:** ```dart -int value = 9007199254740995; +if (nullableBool == true) { +} +if (nullableBool != false) { +} ``` **GOOD:** ```dart -BigInt value = BigInt.parse('9007199254740995'); +if (nullableBool ?? false) { +} +if (nullableBool ?? true) { +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1201.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1201.md index 259fbf64..0d035ca1 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1201.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1201.md @@ -1,22 +1,22 @@ --- -title: "Prefer is! operator." -verbose_name: "prefer_is_not_operator" +title: "Prefer intValue.isOdd/isEven instead of checking the result of % 2" +verbose_name: "use_is_even_rather_than_modulo" category: "antipattern" weight: 70 severity: "major" --- -When checking if an object is not of a specified type, it is preferable to use the 'is!' operator. +**PREFER** the use of intValue.isOdd/isEven to check for evenness. **BAD:** ```dart -if (!(foo is Foo)) { - ... -} +bool isEven = 1 % 2 == 0; +bool isOdd = 13 % 2 == 1; ``` **GOOD:** ```dart -if (foo is! Foo) { - ... -} +bool isEven = 1.isEven; +bool isOdd = 13.isOdd; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1202.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1202.md index 65ceace1..0d1a164d 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1202.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1202.md @@ -1,41 +1,20 @@ --- -title: "Avoid empty catch blocks." -verbose_name: "empty_catches" +title: "Use predefined named constants" +verbose_name: "use_named_constants" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** empty catch blocks. - -In general, empty catch blocks should be avoided. In cases where they are -intended, a comment should be provided to explain why exceptions are being -caught and suppressed. Alternatively, the exception identifier can be named with -underscores (e.g., `_`) to indicate that we intend to skip it. +Where possible, use already defined const values. **BAD:** ```dart -try { - ... -} catch(exception) { } +const Duration(seconds: 0); ``` **GOOD:** ```dart -try { - ... -} catch(e) { - // ignored, really. -} +Duration.zero; +``` -// Alternatively: -try { - ... -} catch(_) { } -// Better still: -try { - ... -} catch(e) { - doSomething(e); -} -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1203.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1203.md index 4c06966f..37697d4e 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1203.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1203.md @@ -1,29 +1,20 @@ --- -title: "Avoid annotating with dynamic when not required." -verbose_name: "avoid_annotating_with_dynamic" +title: "Use raw string to avoid escapes" +verbose_name: "use_raw_strings" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** annotating with dynamic when not required. - -As `dynamic` is the assumed return value of a function or method, it is usually -not necessary to annotate it. +A raw string can be used to avoid escaping only backslashes and dollars. **BAD:** ```dart -dynamic lookUpOrDefault(String name, Map map, dynamic defaultValue) { - var value = map[name]; - if (value != null) return value; - return defaultValue; -} +var s = 'A string with only \\ and \$'; ``` **GOOD:** ```dart -lookUpOrDefault(String name, Map map, defaultValue) { - var value = map[name]; - if (value != null) return value; - return defaultValue; -} +var s = r'A string with only \ and $'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1204.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1204.md index 6e74b30d..cca0f5e5 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1204.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1204.md @@ -1,18 +1,33 @@ --- -title: "Avoid escaping inner quotes by converting surrounding quotes." -verbose_name: "avoid_escaping_inner_quotes" +title: "Use rethrow to rethrow a caught exception" +verbose_name: "use_rethrow_when_possible" category: "antipattern" weight: 70 severity: "major" --- -Avoid escaping inner quotes by converting surrounding quotes. +**DO** use rethrow to rethrow a caught exception. + +As Dart provides rethrow as a feature, it should be used to improve terseness +and readability. **BAD:** ```dart -var s = 'It\'s not fun'; +try { + somethingRisky(); +} catch(e) { + if (!canHandle(e)) throw e; + handle(e); +} ``` **GOOD:** ```dart -var s = "It's not fun"; +try { + somethingRisky(); +} catch(e) { + if (!canHandle(e)) rethrow; + handle(e); +} ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1205.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1205.md index 76b7b8a2..45ef1665 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1205.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1205.md @@ -1,37 +1,22 @@ --- -title: "Declare method return types." -verbose_name: "always_declare_return_types" +title: "Use a setter for operations that conceptually change a property" +verbose_name: "use_setters_to_change_properties" category: "antipattern" weight: 70 severity: "major" --- -**DO** declare method return types. - -When declaring a method or function *always* specify a return type. -Declaring return types for functions helps improve your codebase by allowing the -analyzer to more adequately check your code for errors that could occur during -runtime. +**DO** use a setter for operations that conceptually change a property. **BAD:** ```dart -main() { } - -_bar() => _Foo(); - -class _Foo { - _foo() => 42; -} +rectangle.setWidth(3); +button.setVisible(false); ``` **GOOD:** ```dart -void main() { } - -_Foo _bar() => _Foo(); +rectangle.width = 3; +button.visible = false; +``` -class _Foo { - int _foo() => 42; -} -typedef predicate = bool Function(Object o); -``` diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1206.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1206.md index 162105a5..bab0e482 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1206.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1206.md @@ -1,116 +1,35 @@ --- -title: "Invocation of Iterable.contains with references of unrelated r' types." -verbose_name: "iterable_contains_unrelated_type" -category: "bug-risk" +title: "Use string buffers to compose strings" +verbose_name: "use_string_buffers" +category: "antipattern" weight: 70 severity: "major" --- -**DON'T** invoke `contains` on `Iterable` with an instance of different type -than the parameter type. +**DO** use string buffers to compose strings. -Doing this will invoke `==` on its elements and most likely will return `false`. +In most cases, using a string buffer is preferred for composing strings due to +its improved performance. **BAD:** ```dart -void someFunction() { - var list = []; - if (list.contains('1')) print('someFunction'); // LINT +String foo() { + final buffer = ''; + for (int i = 0; i < 10; i++) { + buffer += 'a'; // LINT + } + return buffer; } ``` -**BAD:** -```dart -void someFunction3() { - List list = []; - if (list.contains('1')) print('someFunction3'); // LINT -} -``` - -**BAD:** -```dart -void someFunction8() { - List list = []; - DerivedClass3 instance; - if (list.contains(instance)) print('someFunction8'); // LINT -} -``` - -**BAD:** -```dart -abstract class SomeIterable implements Iterable {} - -abstract class MyClass implements SomeIterable { - bool badMethod(String thing) => this.contains(thing); // LINT -} -``` - -**GOOD:** -```dart -void someFunction10() { - var list = []; - if (list.contains(1)) print('someFunction10'); // OK -} -``` - -**GOOD:** -```dart -void someFunction1() { - var list = []; - if (list.contains(1)) print('someFunction1'); // OK -} -``` - -**GOOD:** -```dart -void someFunction4() { - List list = []; - if (list.contains(1)) print('someFunction4'); // OK -} -``` - -**GOOD:** -```dart -void someFunction5() { - List list = []; - DerivedClass1 instance; - if (list.contains(instance)) print('someFunction5'); // OK -} - -abstract class ClassBase {} - -class DerivedClass1 extends ClassBase {} -``` - **GOOD:** ```dart -void someFunction6() { - List list = []; - DerivedClass2 instance; - if (list.contains(instance)) print('someFunction6'); // OK +String foo() { + final buffer = StringBuffer(); + for (int i = 0; i < 10; i++) { + buffer.write('a'); + } + return buffer.toString(); } - -abstract class ClassBase {} - -abstract class Mixin {} - -class DerivedClass2 extends ClassBase with Mixin {} ``` -**GOOD:** -```dart -void someFunction7() { - List list = []; - DerivedClass3 instance; - if (list.contains(instance)) print('someFunction7'); // OK -} - -abstract class ClassBase {} - -abstract class Mixin {} - -class DerivedClass3 extends ClassBase implements Mixin {} -``` -**DEPRECATED:** This rule is deprecated in favor of -`collection_methods_unrelated_type`. -The rule will be removed in a future Dart release. diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1207.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1207.md index fe1ebfcb..9ae56168 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1207.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1207.md @@ -1,35 +1,24 @@ --- -title: "Prefer final in for-each loop variable if reference is not reassigned." -verbose_name: "prefer_final_in_for_each" +title: "Use string in part of directives" +verbose_name: "use_string_in_part_of_directives" category: "antipattern" weight: 70 severity: "major" --- -**DO** prefer declaring for-each loop variables as final if they are not -reassigned later in the code. +From [Effective Dart](https://dart.dev/effective-dart/usage#do-use-strings-in-part-of-directives): -Declaring for-each loop variables as final when possible is a good practice -because it helps avoid accidental reassignments and allows the compiler to do -optimizations. +**DO** use strings in `part of` directives. **BAD:** -```dart -for (var element in elements) { // LINT - print('Element: $element'); -} -``` -**GOOD:** ```dart -for (final element in elements) { - print('Element: $element'); -} +part of my_library; ``` **GOOD:** + ```dart -for (var element in elements) { - element = element + element; - print('Element: $element'); -} +part of '../../my_library.dart'; ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1208.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1208.md index 11221997..da4c265f 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1208.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1208.md @@ -1,21 +1,45 @@ --- -title: "Prefer an 8-digit hexadecimal integer(0xFFFFFFFF) to instantiate Color." -verbose_name: "use_full_hex_values_for_flutter_colors" +title: "Use throwsA matcher instead of fail()" +verbose_name: "use_test_throws_matchers" category: "antipattern" weight: 70 severity: "major" --- -**PREFER** an 8-digit hexadecimal integer(0xFFFFFFFF) to instantiate Color. Colors -have four 8-bit channels, which adds up to 32 bits, so Colors are described -using a 32 bit integer. +Use the `throwsA` matcher instead of try-catch with `fail()`. **BAD:** + ```dart -Color(1); -Color(0x000001); +// sync code +try { + someSyncFunctionThatThrows(); + fail('expected Error'); +} on Error catch (error) { + expect(error.message, contains('some message')); +} + +// async code +try { + await someAsyncFunctionThatThrows(); + fail('expected Error'); +} on Error catch (error) { + expect(error.message, contains('some message')); +} ``` **GOOD:** ```dart -Color(0x00000001); +// sync code +expect( + () => someSyncFunctionThatThrows(), + throwsA(isA().having((Error error) => error.message, 'message', contains('some message'))), +); + +// async code +await expectLater( + () => someAsyncFunctionThatThrows(), + throwsA(isA().having((Error error) => error.message, 'message', contains('some message'))), +); ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1209.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1209.md index 5a40e69d..6a21d1f1 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1209.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1209.md @@ -1,28 +1,43 @@ --- -title: "Avoid field initializers in const classes." -verbose_name: "avoid_field_initializers_in_const_classes" +title: "Start the name of the method with to/_to or as/_as if applicable" +verbose_name: "use_to_and_as_if_applicable" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** field initializers in const classes. +From [Effective Dart](https://dart.dev/effective-dart/design#prefer-naming-a-method-to___-if-it-copies-the-objects-state-to-a-new-object): -Instead of `final x = const expr;`, you should write `get x => const expr;` and -not allocate a useless field. As of April 2018 this is true for the VM, but not -for code that will be compiled to JS. +**PREFER** naming a method `to___()` if it copies the object's state to a new +object. + +**PREFER** naming a method `as___()` if it returns a different representation +backed by the original object. **BAD:** ```dart -class A { - final a = const []; - const A(); +class Bar { + Foo myMethod() { + return Foo.from(this); + } +} +``` + +**GOOD:** +```dart +class Bar { + Foo toFoo() { + return Foo.from(this); + } } ``` **GOOD:** ```dart -class A { - get a => const []; - const A(); +class Bar { + Foo asFoo() { + return Foo.from(this); + } } ``` + + diff --git a/analyzers/dart-analyze/.deepsource/issues/DRT-W1210.md b/analyzers/dart-analyze/.deepsource/issues/DRT-W1210.md index acbd25d8..4a5ad8bd 100644 --- a/analyzers/dart-analyze/.deepsource/issues/DRT-W1210.md +++ b/analyzers/dart-analyze/.deepsource/issues/DRT-W1210.md @@ -1,31 +1,23 @@ --- -title: "Avoid catches without on clauses." -verbose_name: "avoid_catches_without_on_clauses" +title: "Don't assign to void" +verbose_name: "void_checks" category: "antipattern" weight: 70 severity: "major" --- -**AVOID** catches without on clauses. - -Using catch clauses without on clauses make your code prone to encountering -unexpected errors that won't be thrown (and thus will go unnoticed). +**DON'T** assign to void. **BAD:** ```dart -try { - somethingRisky() -} -catch(e) { - doSomething(e); +class A { + T value; + void test(T arg) { } } -``` -**GOOD:** -```dart -try { - somethingRisky() -} -on Exception catch(e) { - doSomething(e); +void main() { + A a = A(); + a.value = 1; // LINT + a.test(1); // LINT } ``` +