Skip to content

Commit 6161fd8

Browse files
pqCommit Queue
authored and
Commit Queue
committed
[wildcards] support for prefer_final_locals
Fixes: https://github.com/dart-lang/linter/issues/5042 Change-Id: Icda56e0c8d9c5e0a55a3728311db5e7e3825fa57 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/378573 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Phil Quitslund <[email protected]>
1 parent c8112c5 commit 6161fd8

File tree

2 files changed

+226
-1
lines changed

2 files changed

+226
-1
lines changed

pkg/linter/lib/src/rules/prefer_final_locals.dart

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:analyzer/dart/ast/ast.dart';
66
import 'package:analyzer/dart/ast/visitor.dart';
77
import 'package:analyzer/dart/element/element.dart';
8+
import 'package:analyzer/src/dart/element/extensions.dart'; // ignore: implementation_imports
89

910
import '../analyzer.dart';
1011
import '../extensions.dart';
@@ -151,6 +152,7 @@ class _Visitor extends SimpleAstVisitor<void> {
151152
}
152153
} else {
153154
if (!node.hasPotentiallyMutatedDeclaredVariableInScope(function)) {
155+
if (node.pattern.containsJustWildcards) return;
154156
rule.reportLintForToken(node.keyword);
155157
}
156158
}
@@ -169,7 +171,8 @@ class _Visitor extends SimpleAstVisitor<void> {
169171
}
170172
var declaredElement = variable.declaredElement;
171173
if (declaredElement != null &&
172-
function.isPotentiallyMutatedInScope(declaredElement)) {
174+
(declaredElement.isWildcardVariable ||
175+
function.isPotentiallyMutatedInScope(declaredElement))) {
173176
return;
174177
}
175178
}
@@ -181,6 +184,25 @@ class _Visitor extends SimpleAstVisitor<void> {
181184
}
182185
}
183186

187+
extension on DartPattern {
188+
bool get containsJustWildcards {
189+
var pattern = this;
190+
return switch (pattern) {
191+
ListPattern() => pattern.elements
192+
.every((e) => e is DartPattern && e.containsJustWildcards),
193+
MapPattern() => pattern.elements
194+
.every((e) => e is MapPatternEntry && e.value is WildcardPattern),
195+
ObjectPattern() =>
196+
pattern.fields.every((e) => e.pattern.containsJustWildcards),
197+
ParenthesizedPattern() => pattern.pattern.containsJustWildcards,
198+
RecordPattern() =>
199+
pattern.fields.every((e) => e.pattern.containsJustWildcards),
200+
WildcardPattern() => true,
201+
_ => false,
202+
};
203+
}
204+
}
205+
184206
extension on AstNode {
185207
bool get isDeclaredFinal {
186208
var self = this;

pkg/linter/test/rules/prefer_final_locals_test.dart

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,42 @@ f() {
4444
''');
4545
}
4646

47+
test_destructured_listPattern_wildcard() async {
48+
await assertDiagnostics(r'''
49+
f() {
50+
var [_, b] = ['a', 'b'];
51+
}
52+
''', [
53+
lint(8, 3),
54+
]);
55+
}
56+
57+
test_destructured_listPattern_wildcard_parenthesized() async {
58+
await assertDiagnostics(r'''
59+
f() {
60+
var [(_), b] = ['a', 'b'];
61+
}
62+
''', [
63+
lint(8, 3),
64+
]);
65+
}
66+
67+
test_destructured_listPattern_wildcard_single() async {
68+
await assertNoDiagnostics(r'''
69+
f() {
70+
var [_] = ['a'];
71+
}
72+
''');
73+
}
74+
75+
test_destructured_listPattern_wildcard_single_parenthesized() async {
76+
await assertNoDiagnostics(r'''
77+
f() {
78+
var [(_)] = ['a'];
79+
}
80+
''');
81+
}
82+
4783
test_destructured_listPatternWithRest() async {
4884
await assertDiagnostics(r'''
4985
f() {
@@ -90,6 +126,24 @@ f() {
90126
''');
91127
}
92128

129+
test_destructured_mapPattern_wildcard() async {
130+
await assertDiagnostics(r'''
131+
f() {
132+
var {'first': a, 'second': _} = {'first': 1, 'second': 2};
133+
}
134+
''', [
135+
lint(8, 3),
136+
]);
137+
}
138+
139+
test_destructured_mapPattern_wildcard_single() async {
140+
await assertNoDiagnostics(r'''
141+
f() {
142+
var {'first': _} = {'first': 1};
143+
}
144+
''');
145+
}
146+
93147
test_destructured_objectPattern() async {
94148
await assertDiagnostics(r'''
95149
class A {
@@ -129,6 +183,40 @@ f() {
129183
''');
130184
}
131185

186+
test_destructured_objectPattern_wildcard() async {
187+
await assertNoDiagnostics(r'''
188+
class A {
189+
int a;
190+
A(this.a);
191+
}
192+
f() {
193+
var A(a: _) = A(1);
194+
}
195+
''');
196+
}
197+
198+
test_destructured_objectPattern_wildcard_multipleFields() async {
199+
await assertDiagnostics(r'''
200+
class A {
201+
int a, b;
202+
A(this.a, this.b);
203+
}
204+
f() {
205+
var A(a: x, b: _) = A(1, 2);
206+
}
207+
''', [
208+
lint(53, 3),
209+
]);
210+
}
211+
212+
test_destructured_parenthesizedPattern_wildcard() async {
213+
await assertNoDiagnostics(r'''
214+
f() {
215+
var (_) = ('a');
216+
}
217+
''');
218+
}
219+
132220
test_destructured_recordPattern() async {
133221
await assertDiagnostics(r'''
134222
f() {
@@ -178,6 +266,16 @@ f() {
178266
''');
179267
}
180268

269+
test_destructured_recordPattern_forLoop_wildcard() async {
270+
await assertDiagnostics(r'''
271+
f() {
272+
for (var (_, b) in [(1, 2)]) { }
273+
}
274+
''', [
275+
lint(21, 1),
276+
]);
277+
}
278+
181279
test_destructured_recordPattern_mutated() async {
182280
await assertNoDiagnostics(r'''
183281
f() {
@@ -187,6 +285,24 @@ f() {
187285
''');
188286
}
189287

288+
test_destructured_recordPattern_wildcard() async {
289+
await assertDiagnostics(r'''
290+
f() {
291+
var (_, b) = ('a', 'b');
292+
}
293+
''', [
294+
lint(8, 3),
295+
]);
296+
}
297+
298+
test_destructured_recordPattern_wildcard_multipleWildcards() async {
299+
await assertNoDiagnostics(r'''
300+
f() {
301+
var (_, _) = ('a', 'b');
302+
}
303+
''');
304+
}
305+
190306
test_destructured_recordPattern_withParenthesizedPattern() async {
191307
await assertDiagnostics(r'''
192308
f() {
@@ -223,6 +339,16 @@ f(Object o) {
223339
''');
224340
}
225341

342+
test_ifPatternList_wildcard() async {
343+
await assertDiagnostics(r'''
344+
f(Object o) {
345+
if (o case [int x, int _]) x;
346+
}
347+
''', [
348+
lint(28, 5),
349+
]);
350+
}
351+
226352
test_ifPatternMap() async {
227353
await assertDiagnostics(r'''
228354
f(Object o) {
@@ -241,6 +367,14 @@ f(Object o) {
241367
''');
242368
}
243369

370+
test_ifPatternMap_wildcard() async {
371+
await assertNoDiagnostics(r'''
372+
f(Object o) {
373+
if (o case {'x': var _});
374+
}
375+
''');
376+
}
377+
244378
test_ifPatternObject() async {
245379
await assertDiagnostics(r'''
246380
class C {
@@ -269,6 +403,19 @@ f(Object o) {
269403
''');
270404
}
271405

406+
test_ifPatternObject_wildcard() async {
407+
await assertNoDiagnostics(r'''
408+
class C {
409+
int c;
410+
C(this.c);
411+
}
412+
413+
f(Object o) {
414+
if (o case C(c: var _));
415+
}
416+
''');
417+
}
418+
272419
test_ifPatternRecord() async {
273420
await assertDiagnostics(r'''
274421
f(Object o) {
@@ -288,6 +435,16 @@ f(Object o) {
288435
''');
289436
}
290437

438+
test_ifPatternRecord_wildcard() async {
439+
await assertDiagnostics(r'''
440+
f(Object o) {
441+
if (o case (int x, int _)) x;
442+
}
443+
''', [
444+
lint(28, 5),
445+
]);
446+
}
447+
291448
test_nonDeclaration_destructured_recordPattern() async {
292449
await assertNoDiagnostics(r'''
293450
f(String a, String b) {
@@ -340,6 +497,14 @@ void f() {
340497
]);
341498
}
342499

500+
test_notReassigned_withVar_wildcard() async {
501+
await assertNoDiagnostics(r'''
502+
void f() {
503+
var _ = '';
504+
}
505+
''');
506+
}
507+
343508
test_reassigned() async {
344509
await assertNoDiagnostics(r'''
345510
void f() {
@@ -405,6 +570,24 @@ f() {
405570
''');
406571
}
407572

573+
test_switch_objectPattern_wildcard() async {
574+
await assertDiagnostics(r'''
575+
class A {
576+
int a;
577+
A(this.a);
578+
}
579+
580+
f() {
581+
switch (A(1)) {
582+
case A(a: >0 && var _): print('');
583+
}
584+
}
585+
''', [
586+
// No lint.
587+
error(WarningCode.UNNECESSARY_WILDCARD_PATTERN, 83, 1),
588+
]);
589+
}
590+
408591
test_switch_recordPattern() async {
409592
await assertDiagnostics(r'''
410593
f() {
@@ -435,6 +618,26 @@ f() {
435618
case (var a, final int b): ++a;
436619
}
437620
}
621+
''');
622+
}
623+
624+
test_switch_recordPattern_wildcard() async {
625+
await assertDiagnostics(r'''
626+
f() {
627+
switch ((1, 2)) {
628+
case (var a, int _): a;
629+
}
630+
}
631+
''', [
632+
lint(36, 5),
633+
]);
634+
}
635+
636+
test_wildcardLocal() async {
637+
await assertNoDiagnostics(r'''
638+
f() {
639+
var _ = 0;
640+
}
438641
''');
439642
}
440643
}

0 commit comments

Comments
 (0)