Skip to content

Commit 180ef0d

Browse files
authored
Detect doubled unnecessary_parenthesis, but allow ternary and equality (dart-archive/linter#3887)
* Detect doubled unnecessary_parenthesis, but allow ternary and equality This implements new rules for `unnecessary_parenthesis` lint: * `${( )}` and `(( ))` are never OK, drop the inner ones else, * `(a ? b : c)` is always OK * `(a == b)` and `(a != b)` are OK in assignment-like and return-like statements. * More cases of doubled parentheses and exemptions for equality
1 parent 069fee6 commit 180ef0d

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

lib/src/rules/unnecessary_parenthesis.dart

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,25 @@ class _Visitor extends SimpleAstVisitor<void> {
131131
}
132132
}
133133

134-
if (parent is ParenthesizedExpression) {
134+
// Directly wrapped into parentheses already - always report.
135+
if (parent is ParenthesizedExpression ||
136+
parent is InterpolationExpression ||
137+
(parent is ArgumentList && parent.arguments.length == 1) ||
138+
(parent is IfStatement && node == parent.condition) ||
139+
(parent is IfElement && node == parent.condition) ||
140+
(parent is WhileStatement && node == parent.condition) ||
141+
(parent is DoStatement && node == parent.condition) ||
142+
(parent is SwitchStatement && node == parent.expression) ||
143+
(parent is SwitchExpression && node == parent.expression)) {
135144
rule.reportLint(node);
136145
return;
137146
}
138147

148+
// `(foo ? bar : baz)` is OK.
149+
if (expression is ConditionalExpression) {
150+
return;
151+
}
152+
139153
// `a..b = (c..d)` is OK.
140154
if (expression is CascadeExpression ||
141155
node.thisOrAncestorMatching(
@@ -152,6 +166,19 @@ class _Visitor extends SimpleAstVisitor<void> {
152166
return;
153167
}
154168

169+
// `foo = (a == b)` is OK, `return (count != 0)` is OK.
170+
if (expression is BinaryExpression &&
171+
(expression.operator.type == TokenType.EQ_EQ ||
172+
expression.operator.type == TokenType.BANG_EQ)) {
173+
if (parent is AssignmentExpression ||
174+
parent is VariableDeclaration ||
175+
parent is ReturnStatement ||
176+
parent is YieldStatement ||
177+
parent is ConstructorFieldInitializer) {
178+
return;
179+
}
180+
}
181+
155182
if (parent is Expression) {
156183
if (parent is BinaryExpression) return;
157184
if (parent is ConditionalExpression) return;

test_data/rules/unnecessary_parenthesis.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,54 @@ main() async {
125125
(a?.abs())!;
126126
(a?..abs())!;
127127
(a?[0])!;
128+
129+
print(!({"a": "b"}["a"]!.isEmpty)); // LINT
130+
131+
print((1 + 2)); // LINT
132+
133+
print((1 == 1 ? 2 : 3)); // LINT
134+
print('a'.substring((1 == 1 ? 2 : 3), 4)); // OK
135+
var a1 = (1 == 1 ? 2 : 3); // OK
136+
print('${(1 == 1 ? 2 : 3)}'); // LINT
137+
print([(1 == 1 ? 2 : 3)]); // OK
138+
139+
var a2 = (1 == 1); // OK
140+
a2 = (1 == 1); // OK
141+
a2 = (1 == 1) || "".isEmpty; // OK
142+
var a3 = (1 + 1); // LINT
128143
}
129144

145+
bool testTernaryAndEquality() {
146+
if ((1 == 1 ? true : false)) // LINT
147+
{
148+
return (1 != 1); // OK
149+
} else if ((1 == 1 ? true : false)) // LINT
150+
{
151+
return (1 > 1); // LINT
152+
}
153+
while ((1 == 1)) // LINT
154+
{
155+
print('');
156+
}
157+
switch ((5 == 6)) // LINT
158+
{
159+
case true:
160+
return false;
161+
default:
162+
return true;
163+
}
164+
}
165+
166+
class TestConstructorFieldInitializer {
167+
bool _x, _y;
168+
TestConstructorFieldInitializer()
169+
: _x = (1 == 2), // OK
170+
_y = (true && false); // LINT
171+
}
172+
173+
int test2() => (1 == 1 ? 2 : 3); // OK
174+
bool test3() => (1 == 1); // LINT
175+
130176
Invocation? invocation() => null;
131177

132178
m({p}) => null;

0 commit comments

Comments
 (0)