Skip to content

Commit 1ce0b0e

Browse files
FMorschelCommit Queue
authored andcommitted
[analyzer] Adds new warning for multiple combinators
Fixes: #56879 Change-Id: Ifd53878e3603090efa7905b3cd021b8a63344c26 Tested: trybots Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/413520 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Paul Berry <[email protected]>
1 parent 1a9a35f commit 1ce0b0e

File tree

14 files changed

+265
-8
lines changed

14 files changed

+265
-8
lines changed

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3656,6 +3656,10 @@ WarningCode.MIXIN_ON_SEALED_CLASS:
36563656
notes: |-
36573657
`sealed` annotation is likely to be replaced by the `sealed` keyword
36583658
in the next stable release.
3659+
WarningCode.MULTIPLE_COMBINATORS:
3660+
status: needsFix
3661+
notes: |-
3662+
Aggregate the combinators into a single one.
36593663
WarningCode.MUST_BE_IMMUTABLE:
36603664
status: noFix
36613665
WarningCode.MUST_CALL_SUPER:

pkg/analysis_server/test/services/refactoring/legacy/rename_import_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ void f(Random r) {}
5555
Future<void> test_createChange_add() async {
5656
await indexTestUnit('''
5757
import 'dart:async';
58+
// ignore: multiple_combinators
5859
import 'dart:math' show Random, min hide max;
5960
void f() {
6061
Future f;
@@ -69,6 +70,7 @@ void f() {
6970
// validate change
7071
return assertSuccessfulRefactoring('''
7172
import 'dart:async';
73+
// ignore: multiple_combinators
7274
import 'dart:math' as newName show Random, min hide max;
7375
void f() {
7476
Future f;

pkg/analysis_server/test/src/services/correction/fix/ambiguous_import_fix_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ void foo() {}''');
453453
newFile(join(testPackageLibPath, 'lib2.dart'), '''
454454
void bar() {}''');
455455
await resolveTestCode('''
456+
// ignore: multiple_combinators
456457
import 'lib1.dart' hide baz hide foo;
457458
import 'lib2.dart';
458459
@@ -461,6 +462,7 @@ void foo() {
461462
}
462463
''');
463464
await assertHasFix('''
465+
// ignore: multiple_combinators
464466
import 'lib1.dart' hide baz, bar hide foo, bar;
465467
import 'lib2.dart';
466468
@@ -873,6 +875,7 @@ class O {}''');
873875
newFile(join(testPackageLibPath, 'lib2.dart'), '''
874876
class N {}''');
875877
await resolveTestCode('''
878+
// ignore: multiple_combinators
876879
import 'lib1.dart' show N show N, O, M;
877880
import 'lib2.dart' show N;
878881
@@ -881,6 +884,7 @@ void f(N? n) {
881884
}
882885
''');
883886
await assertHasFix('''
887+
// ignore: multiple_combinators
884888
import 'lib1.dart' show O, M;
885889
import 'lib2.dart' show N;
886890
@@ -896,6 +900,7 @@ class N {}''');
896900
newFile(join(testPackageLibPath, 'lib2.dart'), '''
897901
class N {}''');
898902
await resolveTestCode('''
903+
// ignore: multiple_combinators
899904
import 'lib1.dart' show N show N;
900905
import 'lib2.dart' show N;
901906
@@ -904,6 +909,7 @@ void f(N? n) {
904909
}
905910
''');
906911
await assertHasFix('''
912+
// ignore: multiple_combinators
907913
import 'lib1.dart' hide N;
908914
import 'lib2.dart' show N;
909915
@@ -920,6 +926,7 @@ class N {}''');
920926
newFile(join(testPackageLibPath, 'lib2.dart'), '''
921927
class N {}''');
922928
await resolveTestCode('''
929+
// ignore: multiple_combinators
923930
import 'lib1.dart' show N hide M hide M;
924931
import 'lib2.dart' show N;
925932
@@ -928,6 +935,7 @@ void f(N? n) {
928935
}
929936
''');
930937
await assertHasFix('''
938+
// ignore: multiple_combinators
931939
import 'lib1.dart' hide M, N hide M, N;
932940
import 'lib2.dart' show N;
933941

pkg/analysis_server/test/src/services/correction/fix/remove_name_from_combinator_test.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,15 @@ f(x) {
180180

181181
Future<void> test_undefinedHiddenName_only_first() async {
182182
await resolveTestCode('''
183+
// ignore: multiple_combinators
183184
import 'dart:math' hide aaa hide cos, sin;
184185
185186
void f() {
186187
print(min(0, 1));
187188
}
188189
''');
189190
await assertHasFix('''
191+
// ignore: multiple_combinators
190192
import 'dart:math' hide cos, sin;
191193
192194
void f() {
@@ -197,13 +199,15 @@ void f() {
197199

198200
Future<void> test_undefinedHiddenName_only_last() async {
199201
await resolveTestCode('''
202+
// ignore: multiple_combinators
200203
import 'dart:math' hide cos, sin hide aaa;
201204
202205
void f() {
203206
print(min(0, 1));
204207
}
205208
''');
206209
await assertHasFix('''
210+
// ignore: multiple_combinators
207211
import 'dart:math' hide cos, sin;
208212
209213
void f() {
@@ -214,13 +218,15 @@ void f() {
214218

215219
Future<void> test_undefinedHiddenName_only_middle() async {
216220
await resolveTestCode('''
221+
// ignore: multiple_combinators
217222
import 'dart:math' hide cos hide aaa hide sin;
218223
219224
void f() {
220225
print(min(0, 1));
221226
}
222227
''');
223228
await assertHasFix('''
229+
// ignore: multiple_combinators
224230
import 'dart:math' hide cos hide sin;
225231
226232
void f() {

pkg/analysis_server/test/src/utilities/selection_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ enum E { a }
556556
int a, b, c, d;
557557
''');
558558
var selection = await _computeSelection('''
559+
// ignore: multiple_combinators
559560
export 'a.dart' show a [!hide b show c!] hide d;
560561
''');
561562
_assertSelection(selection, r'''
@@ -790,6 +791,7 @@ nodesInRange
790791
int a, b, c, d;
791792
''');
792793
var selection = await _computeSelection('''
794+
// ignore: multiple_combinators
793795
import 'a.dart' show a [!hide b show c!] hide d;
794796
''');
795797
_assertSelection(selection, r'''

pkg/analyzer/lib/src/error/codes.g.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7043,6 +7043,14 @@ class WarningCode extends ErrorCode {
70437043
hasPublishedDocs: true,
70447044
);
70457045

7046+
/// No parameters.
7047+
static const WarningCode MULTIPLE_COMBINATORS = WarningCode(
7048+
'MULTIPLE_COMBINATORS',
7049+
"Using multiple 'hide' or 'show' combinators is never necessary and often "
7050+
"produces surprising results.",
7051+
correctionMessage: "Try using a single combinator.",
7052+
);
7053+
70467054
/// Generates a warning for classes that inherit from classes annotated with
70477055
/// `@immutable` but that are not immutable.
70487056
///

pkg/analyzer/lib/src/error/error_code_values.g.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,7 @@ const List<ErrorCode> errorCodeValues = [
10521052
WarningCode.MISSING_REQUIRED_PARAM,
10531053
WarningCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
10541054
WarningCode.MIXIN_ON_SEALED_CLASS,
1055+
WarningCode.MULTIPLE_COMBINATORS,
10551056
WarningCode.MUST_BE_IMMUTABLE,
10561057
WarningCode.MUST_CALL_SUPER,
10571058
WarningCode.NON_CONST_ARGUMENT_FOR_CONST_PARAMETER,

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ class EnclosingExecutableContext {
157157
/// and warnings not covered by the parser and resolver.
158158
class ErrorVerifier extends RecursiveAstVisitor<void>
159159
with ErrorDetectionHelpers {
160+
/// The factory used to create diagnostic messages.
161+
static final _diagnosticFactory = DiagnosticFactory();
162+
160163
/// The error reporter by which errors will be reported.
161164
@override
162165
final ErrorReporter errorReporter;
@@ -732,6 +735,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
732735
_checkForAmbiguousExport(node, libraryExport, exportedLibrary);
733736
_checkForExportInternalLibrary(node, libraryExport);
734737
}
738+
_reportForMultipleCombinators(node);
735739
super.visitExportDirective(node);
736740
}
737741

@@ -1078,6 +1082,8 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
10781082
_checkForDeferredImportOfExtensions(node, importElement);
10791083
}
10801084
}
1085+
1086+
_reportForMultipleCombinators(node);
10811087
super.visitImportDirective(node);
10821088
}
10831089

@@ -5203,7 +5209,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
52035209
_hiddenElements!.contains(element)) {
52045210
_hiddenElements!.contains(element);
52055211
errorReporter.reportError(
5206-
DiagnosticFactory().referencedBeforeDeclaration(
5212+
_diagnosticFactory.referencedBeforeDeclaration(
52075213
errorReporter.source,
52085214
nameToken: nameToken,
52095215
element2: element,
@@ -5689,8 +5695,8 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
56895695
if (errorCode == StaticWarningCode.INVALID_NULL_AWARE_OPERATOR) {
56905696
var previousOperator = previousShortCircuitingOperator(target);
56915697
if (previousOperator != null) {
5692-
errorReporter.reportError(DiagnosticFactory()
5693-
.invalidNullAwareAfterShortCircuit(
5698+
errorReporter.reportError(
5699+
_diagnosticFactory.invalidNullAwareAfterShortCircuit(
56945700
errorReporter.source,
56955701
operator.offset,
56965702
endToken.end - operator.offset,
@@ -6481,6 +6487,19 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
64816487
return null;
64826488
}
64836489

6490+
void _reportForMultipleCombinators(NamespaceDirective node) {
6491+
var combinators = node.combinators;
6492+
if (combinators.length > 1) {
6493+
var offset = combinators.beginToken!.offset;
6494+
var length = combinators.endToken!.end - offset;
6495+
errorReporter.atOffset(
6496+
offset: offset,
6497+
length: length,
6498+
errorCode: WarningCode.MULTIPLE_COMBINATORS,
6499+
);
6500+
}
6501+
}
6502+
64846503
void _withEnclosingExecutable(
64856504
ExecutableElement2OrMember element,
64866505
void Function() operation, {

pkg/analyzer/messages.yaml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27704,6 +27704,73 @@ WarningCode:
2770427704
}
2770527705
```
2770627706
TODO(brianwilkerson): Highlight the identifier without the colon.
27707+
MULTIPLE_COMBINATORS:
27708+
problemMessage: "Using multiple 'hide' or 'show' combinators is never necessary and often produces surprising results."
27709+
correctionMessage: "Try using a single combinator."
27710+
hasPublishedDocs: false
27711+
comment: No parameters.
27712+
documentation: |-
27713+
#### Description
27714+
27715+
The analyzer produces this diagnostic when an import or export directive
27716+
contains more than one combinator.
27717+
27718+
#### Examples
27719+
27720+
The following code produces this diagnostic because the second `show`
27721+
combinator hides `List` and `int`:
27722+
27723+
```dart
27724+
import 'dart:core' [!show Future, List, int show Future!];
27725+
27726+
var x = Future.value(1);
27727+
```
27728+
27729+
The following code produces this diagnostic because the second `hide` combinator
27730+
is redundant:
27731+
27732+
```dart
27733+
import 'dart:math' [!hide Random, max, min hide min!];
27734+
27735+
var x = pi;
27736+
```
27737+
27738+
The following codes produce this diagnostic because the `hide` combinator
27739+
is redundant:
27740+
27741+
```dart
27742+
import 'dart:math' [!show Random, max hide min!];
27743+
27744+
var x = max(0, 1);
27745+
var r = Random();
27746+
```
27747+
27748+
The following code produces this diagnostic because the `show` combinator
27749+
already hides `Random` and `max`, so the `hide` combinator is redundant:
27750+
27751+
```dart
27752+
import 'dart:math' [!hide Random, max show min!];
27753+
27754+
var x = min(0, 1);
27755+
```
27756+
27757+
#### Common fixes
27758+
27759+
If you prefer to list the names that should be visible, then use a single `show` combinator:
27760+
27761+
```dart
27762+
import 'dart:math' show min;
27763+
27764+
var x = min(0, 1);
27765+
```
27766+
27767+
If you prefer to list the names that should be hidden, then use a single `hide` combinator:
27768+
27769+
```dart
27770+
import 'dart:math' hide Random, max, min;
27771+
27772+
var x = pi;
27773+
```
2770727774
UNUSED_LOCAL_VARIABLE:
2770827775
problemMessage: "The value of the local variable '{0}' isn't used."
2770927776
correctionMessage: Try removing the variable or using it.

pkg/analyzer/test/src/diagnostics/duplicate_import_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ M.A a = M.A();
135135

136136
await assertErrorsInFile2(lib1, []);
137137
await assertErrorsInFile2(lib2, [
138+
error(WarningCode.MULTIPLE_COMBINATORS, 35, 13),
138139
error(WarningCode.DUPLICATE_IMPORT, 57, 11),
140+
error(WarningCode.MULTIPLE_COMBINATORS, 74, 13),
139141
]);
140142
}
141143

0 commit comments

Comments
 (0)