Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

Fix cascade_invocations false positive when examining complicated expressions #1328

Merged
merged 2 commits into from
Dec 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 41 additions & 6 deletions lib/src/rules/cascade_invocations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ Element _getPrefixElementFromExpression(Expression rawExpression) {
return DartTypeUtilities.getCanonicalElementFromIdentifier(
expression.prefix);
} else if (expression is PropertyAccess &&
_isInvokedWithoutNullAwareOperator(expression.operator)) {
_isInvokedWithoutNullAwareOperator(expression.operator) &&
expression.target is SimpleIdentifier) {
return DartTypeUtilities.getCanonicalElementFromIdentifier(
expression.target);
}
Expand Down Expand Up @@ -121,7 +122,14 @@ class _CascadableExpression {
null, [],
canJoin: false, canReceive: false, canBeCascaded: false);

/// Whether this expression can be joined with a previous expression via a
/// cascade operation.
final bool canJoin;

/// Whether this expression can receive an additional expression with a
/// cascade operation.
///
/// For example, `a.b = 1` can receive, but `a = 1` cannot receive.
final bool canReceive;
final bool canBeCascaded;

Expand Down Expand Up @@ -178,7 +186,7 @@ class _CascadableExpression {
isCritical: true);
}
// setters
final variable = _getPrefixElementFromExpression(node.leftHandSide);
final variable = _getPrefixElementFromExpression(leftExpression);
final canReceive = node.operator.type != TokenType.QUESTION_QUESTION_EQ &&
variable is VariableElement &&
!variable.isStatic;
Expand Down Expand Up @@ -212,17 +220,44 @@ class _CascadableExpression {
DartTypeUtilities.getCanonicalElementFromIdentifier(node.prefix), [],
canJoin: true, canReceive: true, canBeCascaded: true);

factory _CascadableExpression._fromPropertyAccess(PropertyAccess node) =>
new _CascadableExpression._internal(
DartTypeUtilities.getCanonicalElementFromIdentifier(node.target), [],
canJoin: true, canReceive: true, canBeCascaded: true);
factory _CascadableExpression._fromPropertyAccess(PropertyAccess node) {
var targetIsSimple = node.target is SimpleIdentifier;
return new _CascadableExpression._internal(
DartTypeUtilities.getCanonicalElementFromIdentifier(node.target), [],
// If the target is something like `(a + b).x`, then node can neither
// join, nor receive.
//
// This restriction is quite limiting. It means that this rule cannot
// report on the following code:
//
// b1.a
// ..f = 1
// ..g = 1;
// b2.a.f = 2; // Could report here.
//
// But it may be difficult to accurately know if complicated
// expressions are cascadable. Just because two expressions are "equal"
// or look the same, does not mean they can be cascaded; for example:
//
// (b1 + b2).a
// ..f = 1
// ..g = 1;
// (b1 + b2).a.f = 2; // Should not report here.
//
// TODO(srawlins): Look into whether this is possible.
canJoin: targetIsSimple,
canReceive: targetIsSimple,
canBeCascaded: true);
}

_CascadableExpression._internal(this.element, this.criticalNodes,
{this.canJoin,
this.canReceive,
this.canBeCascaded,
this.isCritical = false});

/// Whether [this] is compatible to be joined with [expressionBox] with a
/// cascade operation.
bool compatibleWith(_CascadableExpression expressionBox) =>
element != null &&
expressionBox.canReceive &&
Expand Down
36 changes: 35 additions & 1 deletion test/rules/cascade_invocations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void cascadeStatic() {
StaticFoo.decrement();
}

// Bug 339
// https://github.com/dart-lang/linter/issues/339
class Identifier339 {
String value;
String system;
Expand Down Expand Up @@ -194,3 +194,37 @@ void function694() {
Bug694.bar = 2;
Bug694.foo = 3; // OK
}

class A {
int f;
int g;

int get p => 7;
int get q => 6;
}

class B {
final A a = A();

B operator +(other) {
return B();
}
}

// https://github.com/dart-lang/linter/issues/1323
void bug1323() {
final B b1 = B();
final B b2 = B();

b1.a
..f = 1
..g = 1;
b2.a.f = 2; // OK

print('buffer statement.');

b1.a
..p
..q;
b2.a.p; // OK
}