@@ -79,7 +79,8 @@ Element _getPrefixElementFromExpression(Expression rawExpression) {
79
79
return DartTypeUtilities .getCanonicalElementFromIdentifier (
80
80
expression.prefix);
81
81
} else if (expression is PropertyAccess &&
82
- _isInvokedWithoutNullAwareOperator (expression.operator )) {
82
+ _isInvokedWithoutNullAwareOperator (expression.operator ) &&
83
+ expression.target is SimpleIdentifier ) {
83
84
return DartTypeUtilities .getCanonicalElementFromIdentifier (
84
85
expression.target);
85
86
}
@@ -121,7 +122,14 @@ class _CascadableExpression {
121
122
null , [],
122
123
canJoin: false , canReceive: false , canBeCascaded: false );
123
124
125
+ /// Whether this expression can be joined with a previous expression via a
126
+ /// cascade operation.
124
127
final bool canJoin;
128
+
129
+ /// Whether this expression can receive an additional expression with a
130
+ /// cascade operation.
131
+ ///
132
+ /// For example, `a.b = 1` can receive, but `a = 1` cannot receive.
125
133
final bool canReceive;
126
134
final bool canBeCascaded;
127
135
@@ -178,7 +186,7 @@ class _CascadableExpression {
178
186
isCritical: true );
179
187
}
180
188
// setters
181
- final variable = _getPrefixElementFromExpression (node.leftHandSide );
189
+ final variable = _getPrefixElementFromExpression (leftExpression );
182
190
final canReceive = node.operator .type != TokenType .QUESTION_QUESTION_EQ &&
183
191
variable is VariableElement &&
184
192
! variable.isStatic;
@@ -212,17 +220,44 @@ class _CascadableExpression {
212
220
DartTypeUtilities .getCanonicalElementFromIdentifier (node.prefix), [],
213
221
canJoin: true , canReceive: true , canBeCascaded: true );
214
222
215
- factory _CascadableExpression ._fromPropertyAccess (PropertyAccess node) =>
216
- new _CascadableExpression ._internal (
217
- DartTypeUtilities .getCanonicalElementFromIdentifier (node.target), [],
218
- canJoin: true , canReceive: true , canBeCascaded: true );
223
+ factory _CascadableExpression ._fromPropertyAccess (PropertyAccess node) {
224
+ var targetIsSimple = node.target is SimpleIdentifier ;
225
+ return new _CascadableExpression ._internal (
226
+ DartTypeUtilities .getCanonicalElementFromIdentifier (node.target), [],
227
+ // If the target is something like `(a + b).x`, then node can neither
228
+ // join, nor receive.
229
+ //
230
+ // This restriction is quite limiting. It means that this rule cannot
231
+ // report on the following code:
232
+ //
233
+ // b1.a
234
+ // ..f = 1
235
+ // ..g = 1;
236
+ // b2.a.f = 2; // Could report here.
237
+ //
238
+ // But it may be difficult to accurately know if complicated
239
+ // expressions are cascadable. Just because two expressions are "equal"
240
+ // or look the same, does not mean they can be cascaded; for example:
241
+ //
242
+ // (b1 + b2).a
243
+ // ..f = 1
244
+ // ..g = 1;
245
+ // (b1 + b2).a.f = 2; // Should not report here.
246
+ //
247
+ // TODO(srawlins): Look into whether this is possible.
248
+ canJoin: targetIsSimple,
249
+ canReceive: targetIsSimple,
250
+ canBeCascaded: true );
251
+ }
219
252
220
253
_CascadableExpression ._internal (this .element, this .criticalNodes,
221
254
{this .canJoin,
222
255
this .canReceive,
223
256
this .canBeCascaded,
224
257
this .isCritical = false });
225
258
259
+ /// Whether [this] is compatible to be joined with [expressionBox] with a
260
+ /// cascade operation.
226
261
bool compatibleWith (_CascadableExpression expressionBox) =>
227
262
element != null &&
228
263
expressionBox.canReceive &&
0 commit comments