Skip to content

Commit c6e3e7a

Browse files
authored
cons tearoff support for unnecessary_parenthesis (dart-archive/linter#2926)
1 parent bc1a886 commit c6e3e7a

File tree

2 files changed

+119
-4
lines changed

2 files changed

+119
-4
lines changed

lib/src/rules/unnecessary_parenthesis.dart

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ class _Visitor extends SimpleAstVisitor<void> {
4848

4949
@override
5050
void visitParenthesizedExpression(ParenthesizedExpression node) {
51-
if (node.expression is SimpleIdentifier) {
52-
var parent = node.parent;
51+
var parent = node.parent;
52+
var expression = node.expression;
53+
if (expression is SimpleIdentifier) {
5354
if (parent is PropertyAccess) {
5455
if (parent.propertyName.name == 'hashCode' ||
5556
parent.propertyName.name == 'runtimeType') {
@@ -67,15 +68,21 @@ class _Visitor extends SimpleAstVisitor<void> {
6768
return;
6869
}
6970

70-
var parent = node.parent;
71+
if (expression is ConstructorReference) {
72+
if (parent is! FunctionExpressionInvocation ||
73+
parent.typeArguments == null) {
74+
rule.reportLint(node);
75+
return;
76+
}
77+
}
7178

7279
if (parent is ParenthesizedExpression) {
7380
rule.reportLint(node);
7481
return;
7582
}
7683

7784
// `a..b=(c..d)` is OK.
78-
if (node.expression is CascadeExpression ||
85+
if (expression is CascadeExpression ||
7986
node.thisOrAncestorMatching(
8087
(n) => n is Statement || n is CascadeExpression)
8188
is CascadeExpression) {
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// test w/ `dart test -N unnecessary_parenthesis.dart`
6+
7+
import 'dart:async';
8+
9+
class D {
10+
D.d([int? x, int? y]);
11+
}
12+
13+
/// https://github.com/dart-lang/linter/issues/2907
14+
void constructorTearOffs() {
15+
var makeD = D.d;
16+
(makeD)(1); // LINT
17+
(D.d)(1); // LINT
18+
(List<int>.filled)(3, 0); // LINT
19+
(List.filled)<int>(3, 0); // OK
20+
var tearoff = (List<int>.filled); // LINT
21+
(List<int>).toString(); //OK
22+
}
23+
24+
var a, b, c, d;
25+
26+
main() async {
27+
1; // OK
28+
(1); // LINT
29+
print(1); // OK
30+
print((1)); // LINT
31+
if (a && b || c && d) true; // OK
32+
// OK because it may be hard to know all of the precedence rules.
33+
if ((a && b) || c && d) true; // OK
34+
(await new Future.value(1)).toString(); // OK
35+
('' as String).toString(); // OK
36+
!(true as bool); // OK
37+
a = (a); // LINT
38+
(a) ? true : false; // LINT
39+
true ? (a) : false; // LINT
40+
true ? true : (a); // LINT
41+
// OK because it is unobvious that the space-involving ternary binds tighter
42+
// than the cascade.
43+
(true ? [] : [])..add(''); // OK
44+
(a ?? true) ? true : true; // OK
45+
true ? [] : []
46+
..add(''); // OK
47+
m(p: (1 + 3)); // LINT
48+
(a++).toString(); // OK
49+
50+
// OK because it is unobvious where cascades fall in precedence.
51+
a..b = (c..d); // OK
52+
a.b = (c..d); // OK
53+
a..b = (c.d); // OK
54+
((x) => x is bool ? x : false)(a); // OK
55+
(fn)(a); // LINT
56+
57+
// OK because unary operators mixed with space-separated tokens may have
58+
// unexpected ordering.
59+
!(const [7].contains(42)); // OK
60+
!(new List(3).contains(42)); // OK
61+
!(await Future.value(false)); // OK
62+
-(new List(3).length); // OK
63+
!(new List(3).length.isEven); // OK
64+
-(new List(3).length.abs().abs().abs()); // OK
65+
-(new List(3).length.sign.sign.sign); // OK
66+
!(const [7]).contains(42); // OK
67+
68+
// OK because some methods are defined on Type, but removing the parentheses
69+
// would attempt to call a _static_ method on the target.
70+
(String).hashCode;
71+
(int).runtimeType;
72+
(bool).noSuchMethod();
73+
(double).toString();
74+
75+
({false: 'false', true: 'true'}).forEach((k, v) => print('$k: $v'));
76+
({false, true}).forEach(print);
77+
({false, true}).length;
78+
print(({1, 2, 3}).length); // LINT
79+
([false, true]).forEach(print); // LINT
80+
}
81+
82+
m({p}) => null;
83+
84+
bool Function(dynamic) get fn => (x) => x is bool ? x : false;
85+
86+
class ClassWithFunction {
87+
Function f;
88+
int number;
89+
90+
ClassWithFunction.named(int a) : this.number = (a + 2); // LINT
91+
// https://github.com/dart-lang/linter/issues/1473
92+
ClassWithFunction.named2(Function value) : this.f = (value ?? (_) => 42); // OK
93+
}
94+
95+
class ClassWithClassWithFunction {
96+
ClassWithFunction c;
97+
98+
// https://github.com/dart-lang/linter/issues/1395
99+
ClassWithClassWithFunction() : c = (ClassWithFunction()..f = () => 42); // OK
100+
}
101+
102+
class UnnecessaryParenthesis {
103+
ClassWithClassWithFunction c;
104+
105+
UnnecessaryParenthesis()
106+
: c = (ClassWithClassWithFunction()
107+
..c = ClassWithFunction().f = () => 42); // OK
108+
}

0 commit comments

Comments
 (0)