Skip to content

Commit 3887c99

Browse files
alexeieleusisJPaulsen
authored andcommitted
Merge pull request dart-archive#412 from alexeieleusis/337_postfixExpression
invariant_boolean: When searching for references reassignment include PostfixExpression and similar, e.g. variable++.
2 parents 7bdebfd + 57ad3cc commit 3887c99

File tree

4 files changed

+118
-12
lines changed

4 files changed

+118
-12
lines changed

lib/src/rules/invariant_booleans.dart

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,29 @@ AstNodePredicate _isConditionalStatementWithReturn(
216216
AstNodePredicate _noFurtherAssignmentInvalidatingCondition(
217217
Expression node, Iterable<AstNode> nodesInDFS) {
218218
Set<Identifier> identifiers = _findStatementIdentifiers(node.parent);
219-
return (AstNode statement) =>
220-
nodesInDFS
221-
.skipWhile((n) => n != statement)
222-
.takeWhile((n) => n != node)
223-
.where((n) =>
224-
n is AssignmentExpression &&
225-
!identifiers.contains(n.leftHandSide))
226-
.length ==
227-
0;
219+
return (AstNode statement) {
220+
bool isMutation(AstNode n) {
221+
if (n is AssignmentExpression) {
222+
return !identifiers.contains(n.leftHandSide);
223+
} else if (n is PostfixExpression) {
224+
TokenType type = n.operator.type;
225+
return (type == TokenType.PLUS_PLUS || type == TokenType.MINUS_MINUS) &&
226+
!identifiers.contains(n.operand);
227+
} else if (n is PrefixExpression) {
228+
TokenType type = n.operator.type;
229+
return (type == TokenType.PLUS_PLUS || type == TokenType.MINUS_MINUS) &&
230+
!identifiers.contains(n.operand);
231+
}
232+
233+
return false;
234+
}
235+
236+
return nodesInDFS
237+
.skipWhile((n) => n != statement)
238+
.takeWhile((n) => n != node)
239+
.where(isMutation)
240+
.isEmpty;
241+
};
228242
}
229243

230244
List<Expression> _splitConjunctions(Expression expression) {

lib/src/rules/unnecessary_lambdas.dart

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
library linter.src.rules.unnecessary_lambdas;
66

77
import 'package:analyzer/dart/ast/ast.dart';
8+
import 'package:analyzer/dart/ast/token.dart';
89
import 'package:analyzer/dart/ast/visitor.dart';
910
import 'package:analyzer/dart/element/element.dart';
1011
import 'package:linter/src/analyzer.dart';
@@ -36,6 +37,13 @@ Iterable<Element> _extractElementsOfSimpleIdentifiers(AstNode node) =>
3637
.where((e) => e is SimpleIdentifier)
3738
.map((e) => (e as SimpleIdentifier).staticElement);
3839

40+
bool _hasQuestionPeriod(AstNode node) {
41+
return (node is PropertyAccess &&
42+
node.operator?.type == TokenType.QUESTION_PERIOD) ||
43+
(node is MethodInvocation &&
44+
node.operator?.type == TokenType.QUESTION_PERIOD);
45+
}
46+
3947
class UnnecessaryLambdas extends LintRule {
4048
_Visitor _visitor;
4149

@@ -56,6 +64,11 @@ class _Visitor extends SimpleAstVisitor {
5664
final LintRule rule;
5765
_Visitor(this.rule);
5866

67+
@override
68+
visitCompilationUnit(CompilationUnit node) {
69+
var a = DartTypeUtilities.traverseNodesInDFS(node);
70+
}
71+
5972
@override
6073
void visitFunctionExpression(FunctionExpression node) {
6174
if (node.element.name != '') {
@@ -80,16 +93,17 @@ class _Visitor extends SimpleAstVisitor {
8093

8194
void _visitInvocationExpression(
8295
InvocationExpression node, FunctionExpression nodeToLint) {
83-
if (nodeToLint.parameters.length != node.argumentList.length) {
96+
if (nodeToLint.parameters.length !=
97+
node.argumentList.length) {
8498
return;
8599
}
86100
if (node.argumentList.arguments.any((e) => e is! SimpleIdentifier)) {
87101
return;
88102
}
89103
final parameters =
90-
nodeToLint.parameters.parameters.map((e) => e.identifier.staticElement);
104+
nodeToLint.parameters.parameters.map((e) => e.identifier.bestElement);
91105
final arguments = node.argumentList.arguments
92-
.map((e) => (e as SimpleIdentifier).staticElement);
106+
.map((e) => (e as SimpleIdentifier).bestElement);
93107
for (int i = 0; i < parameters.length; i++) {
94108
if (parameters.elementAt(i) != arguments.elementAt(i)) {
95109
return;
@@ -99,6 +113,13 @@ class _Visitor extends SimpleAstVisitor {
99113
if (node is FunctionExpressionInvocation) {
100114
restOfElements = _extractElementsOfSimpleIdentifiers(node.function);
101115
} else if (node is MethodInvocation && node.target != null) {
116+
if (_hasQuestionPeriod(node) ||
117+
_hasQuestionPeriod(node.target) ||
118+
DartTypeUtilities
119+
.traverseNodesInDFS(node.target)
120+
.any(_hasQuestionPeriod)) {
121+
return;
122+
}
102123
restOfElements = node.target is SimpleIdentifier
103124
? [(node.target as SimpleIdentifier).staticElement]
104125
: _extractElementsOfSimpleIdentifiers(node.target);

test/rules/invariant_booleans.dart

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,56 @@ void bug372(bool foo) {
237237
// doSomethingElse();
238238
}
239239
}
240+
241+
void bug337_1(int offset, int length) {
242+
if (offset >= length) {
243+
return;
244+
}
245+
246+
offset++;
247+
if (offset >= length) { // OK
248+
}
249+
}
250+
251+
void bug337_2(int offset, int length) {
252+
if (offset >= length) {
253+
return;
254+
}
255+
256+
offset--;
257+
if (offset >= length) { // OK
258+
}
259+
}
260+
261+
void bug337_3(int offset, int length) {
262+
if (offset >= length) {
263+
return;
264+
}
265+
266+
++offset;
267+
if (offset >= length) { // OK
268+
}
269+
}
270+
271+
void bug337_4(int offset, int length) {
272+
if (offset >= length) {
273+
return;
274+
}
275+
276+
--offset;
277+
if (offset >= length) { // OK
278+
}
279+
}
280+
281+
void test337_5() {
282+
int b = 2;
283+
if (b > 0) {
284+
b--;
285+
if (b == 0) {
286+
return;
287+
}
288+
if (b > 0) {
289+
return;
290+
}
291+
}
292+
}

test/rules/unnecessary_lambdas.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
// test w/ `pub run test -N unnecessary_lambdas`
66

7+
Function stateList<T>(String finder) {
8+
return (String element) => _stateOf<T>(element, finder);
9+
}
10+
11+
Iterable<T> _stateOf<T>(String element, String finder) {
12+
return <T>[];
13+
}
14+
715
void main() {
816
List<String> names = [];
917

@@ -38,6 +46,16 @@ void main() {
3846
var deeplyNestedVariable = (a, b) { // OK
3947
foo(foo(b)).foo(a, b);
4048
};
49+
50+
51+
// ignore: unused_local_variable
52+
var caseWithNullCheck1 = () => names?.first.toLowerCase(); // OK
53+
54+
// ignore: unused_local_variable
55+
var caseWithNullCheck2 = () => names.first?.toLowerCase(); // OK
56+
57+
// ignore: unused_local_variable
58+
var caseWithTwoNullChecks = () => names?.first?.toLowerCase(); // OK
4159
}
4260

4361
foo(a) {

0 commit comments

Comments
 (0)