Skip to content

Lint that warns about uses of cascade notation that are counter intuitive #58532

@jacob314

Description

@jacob314

Combining dart cascade notation with normal method invocations results in expressions that don't evaluate how users expect. dartfmt helps a bit by enforcing indentation that clarifies the precedence a bit but results can still be confusing.

Examples of confused users:
https://stackoverflow.com/questions/17025769/how-do-method-cascades-work-exactly-in-dart

myList..clear().addAll(otherList)

gives an error that it cannot call addAll on null (if myList is dynamic).

A().b..c.d..runtimeType
A().b.c..foo()..bar(); // For discussion. Including all . before all .. might be ok or we could force parens in this case as well to fully disambiguate.

does not return runtimeType.

This is because cascade has an extremely low operator precedence which is surprising to users as . and .. seems similar but have very different precedence.
https://dart.dev/guides/language/language-tour#operators
The only operator that .. plays with consistently is = as it is given lower precedence than .

A lint and quickfix could help ease the way towards future Dart support for more intuitive precedence rules for cascades. The most aggressive version of the lint could force adding parenthesis for all cases where the expression order for cascades is required to get the current behavior.

Possible lint messages:
"If you end a cascade section with a getter you're going to have a bad time"
"Expression contains cascades without parenthesis to disambiguate the order of operations"

These lints would be used by any Dart user that uses cascades. We are seeing more Dart users use cascades as some Dart test frameworks now strongly benefit from using cascades but also result in more abuse of cascades.

An existing nice lint for cascades is
https://dart-lang.github.io/linter/lints/avoid_single_cascade_in_expression_statements.html

A quickfix could add parens so that the code no longer depends on the surprising order of operations for cascades.

Examples

A().b..c.d..runtimeType // Error
A().b..c.d..someMethod() // Error
((A().b..c).d)..someMethod() // No error as parens disambiguate
A()..b()..c()..d() // no error as calls do not mix . and ..

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3A lower priority bug or feature requestarea-devexpFor issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.devexp-linterIssues with the analyzer's support for the linter packagetype-enhancementA request for a change that isn't a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions