Skip to content

Commit 11a25ca

Browse files
asashourCommit Queue
authored and
Commit Queue
committed
Reland "[analyzer] add UNNECESSARY_NAN_COMPARISON hint"
This is a reland of commit 254da67 Original change's description: > [analyzer] add `UNNECESSARY_NAN_COMPARISON` hint > > Fixes #44649 > > Change-Id: I3784f7222a217e5b6ca485c02e9a889964ffcc8c > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/269881 > Commit-Queue: Brian Wilkerson <[email protected]> > Reviewed-by: Brian Wilkerson <[email protected]> Change-Id: I868d46df69f178094742d9193de5d347ea2cc60b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278440 Reviewed-by: Oleh Prypin <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 5b50a61 commit 11a25ca

File tree

8 files changed

+138
-6
lines changed

8 files changed

+138
-6
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,14 @@ HintCode.UNNECESSARY_IGNORE:
16371637
Remove the ignore comment (or one code in the comment).
16381638
HintCode.UNNECESSARY_IMPORT:
16391639
status: hasFix
1640+
HintCode.UNNECESSARY_NAN_COMPARISON_FALSE:
1641+
status: needsFix
1642+
notes: |-
1643+
Use 'isNaN', or remove the comparison.
1644+
HintCode.UNNECESSARY_NAN_COMPARISON_TRUE:
1645+
status: needsFix
1646+
notes: |-
1647+
Use 'isNaN', or remove the comparison.
16401648
HintCode.UNNECESSARY_NO_SUCH_METHOD:
16411649
status: needsFix
16421650
notes: |-

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,22 @@ class HintCode extends AnalyzerErrorCode {
12331233
hasPublishedDocs: true,
12341234
);
12351235

1236+
/// No parameters.
1237+
static const HintCode UNNECESSARY_NAN_COMPARISON_FALSE = HintCode(
1238+
'UNNECESSARY_NAN_COMPARISON',
1239+
"A double can't equal NaN, so the condition is always 'false'.",
1240+
correctionMessage: "Try using 'isNan', or removing the condition.",
1241+
uniqueName: 'UNNECESSARY_NAN_COMPARISON_FALSE',
1242+
);
1243+
1244+
/// No parameters.
1245+
static const HintCode UNNECESSARY_NAN_COMPARISON_TRUE = HintCode(
1246+
'UNNECESSARY_NAN_COMPARISON',
1247+
"A double can't equal NaN, so the condition is always 'true'.",
1248+
correctionMessage: "Try using 'isNan', or removing the condition.",
1249+
uniqueName: 'UNNECESSARY_NAN_COMPARISON_TRUE',
1250+
);
1251+
12361252
/// No parameters.
12371253
static const HintCode UNNECESSARY_NO_SUCH_METHOD = HintCode(
12381254
'UNNECESSARY_NO_SUCH_METHOD',
@@ -1244,7 +1260,7 @@ class HintCode extends AnalyzerErrorCode {
12441260
/// No parameters.
12451261
static const HintCode UNNECESSARY_NULL_COMPARISON_FALSE = HintCode(
12461262
'UNNECESSARY_NULL_COMPARISON',
1247-
"The operand can't be null, so the condition is always false.",
1263+
"The operand can't be null, so the condition is always 'false'.",
12481264
correctionMessage:
12491265
"Try removing the condition, an enclosing condition, or the whole "
12501266
"conditional statement.",
@@ -1255,7 +1271,7 @@ class HintCode extends AnalyzerErrorCode {
12551271
/// No parameters.
12561272
static const HintCode UNNECESSARY_NULL_COMPARISON_TRUE = HintCode(
12571273
'UNNECESSARY_NULL_COMPARISON',
1258-
"The operand can't be null, so the condition is always true.",
1274+
"The operand can't be null, so the condition is always 'true'.",
12591275
correctionMessage: "Remove the condition.",
12601276
hasPublishedDocs: true,
12611277
uniqueName: 'UNNECESSARY_NULL_COMPARISON_TRUE',

pkg/analyzer/lib/src/error/best_practices_verifier.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
372372
void visitBinaryExpression(BinaryExpression node) {
373373
_checkForDivisionOptimizationHint(node);
374374
_deprecatedVerifier.binaryExpression(node);
375+
_checkForInvariantNanComparison(node);
375376
_checkForInvariantNullComparison(node);
376377
_invalidAccessVerifier.verifyBinary(node);
377378
super.visitBinaryExpression(node);
@@ -1207,6 +1208,40 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
12071208
}
12081209
}
12091210

1211+
void _checkForInvariantNanComparison(BinaryExpression node) {
1212+
void reportStartEnd(
1213+
HintCode errorCode,
1214+
SyntacticEntity startEntity,
1215+
SyntacticEntity endEntity,
1216+
) {
1217+
var offset = startEntity.offset;
1218+
_errorReporter.reportErrorForOffset(
1219+
errorCode,
1220+
offset,
1221+
endEntity.end - offset,
1222+
);
1223+
}
1224+
1225+
bool isDoubleNan(Expression expression) =>
1226+
expression is PrefixedIdentifier &&
1227+
expression.prefix.name == 'double' &&
1228+
expression.identifier.name == 'nan';
1229+
1230+
void checkLeftRight(HintCode errorCode) {
1231+
if (isDoubleNan(node.leftOperand)) {
1232+
reportStartEnd(errorCode, node.leftOperand, node.operator);
1233+
} else if (isDoubleNan(node.rightOperand)) {
1234+
reportStartEnd(errorCode, node.operator, node.rightOperand);
1235+
}
1236+
}
1237+
1238+
if (node.operator.type == TokenType.BANG_EQ) {
1239+
checkLeftRight(HintCode.UNNECESSARY_NAN_COMPARISON_TRUE);
1240+
} else if (node.operator.type == TokenType.EQ_EQ) {
1241+
checkLeftRight(HintCode.UNNECESSARY_NAN_COMPARISON_FALSE);
1242+
}
1243+
}
1244+
12101245
void _checkForInvariantNullComparison(BinaryExpression node) {
12111246
if (!_isNonNullableByDefault) return;
12121247

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@ const List<ErrorCode> errorCodeValues = [
670670
HintCode.UNNECESSARY_FINAL,
671671
HintCode.UNNECESSARY_IGNORE,
672672
HintCode.UNNECESSARY_IMPORT,
673+
HintCode.UNNECESSARY_NAN_COMPARISON_FALSE,
674+
HintCode.UNNECESSARY_NAN_COMPARISON_TRUE,
673675
HintCode.UNNECESSARY_NO_SUCH_METHOD,
674676
HintCode.UNNECESSARY_NULL_COMPARISON_FALSE,
675677
HintCode.UNNECESSARY_NULL_COMPARISON_TRUE,

pkg/analyzer/messages.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20962,6 +20962,18 @@ HintCode:
2096220962
If some of the names imported by this import are intended to be used but
2096320963
aren't yet, and if those names aren't imported by other imports, then add
2096420964
the missing references to those names.
20965+
UNNECESSARY_NAN_COMPARISON_FALSE:
20966+
sharedName: UNNECESSARY_NAN_COMPARISON
20967+
problemMessage: "A double can't equal NaN, so the condition is always 'false'."
20968+
correctionMessage: Try using 'isNan', or removing the condition.
20969+
hasPublishedDocs: false
20970+
comment: No parameters.
20971+
UNNECESSARY_NAN_COMPARISON_TRUE:
20972+
sharedName: UNNECESSARY_NAN_COMPARISON
20973+
problemMessage: "A double can't equal NaN, so the condition is always 'true'."
20974+
correctionMessage: Try using 'isNan', or removing the condition.
20975+
hasPublishedDocs: false
20976+
comment: No parameters.
2096520977
UNNECESSARY_NO_SUCH_METHOD:
2096620978
problemMessage: "Unnecessary 'noSuchMethod' declaration."
2096720979
correctionMessage: "Try removing the declaration of 'noSuchMethod'."
@@ -21013,7 +21025,7 @@ HintCode:
2101321025
```
2101421026
UNNECESSARY_NULL_COMPARISON_FALSE:
2101521027
sharedName: UNNECESSARY_NULL_COMPARISON
21016-
problemMessage: "The operand can't be null, so the condition is always false."
21028+
problemMessage: "The operand can't be null, so the condition is always 'false'."
2101721029
correctionMessage: Try removing the condition, an enclosing condition, or the whole conditional statement.
2101821030
hasPublishedDocs: true
2101921031
comment: No parameters.
@@ -21071,7 +21083,7 @@ HintCode:
2107121083
```
2107221084
UNNECESSARY_NULL_COMPARISON_TRUE:
2107321085
sharedName: UNNECESSARY_NULL_COMPARISON
21074-
problemMessage: "The operand can't be null, so the condition is always true."
21086+
problemMessage: "The operand can't be null, so the condition is always 'true'."
2107521087
correctionMessage: Remove the condition.
2107621088
hasPublishedDocs: true
2107721089
comment: No parameters.

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ import 'unnecessary_cast_test.dart' as unnecessary_cast;
794794
import 'unnecessary_final_test.dart' as unnecessary_final;
795795
import 'unnecessary_ignore_test.dart' as unnecessary_ignore;
796796
import 'unnecessary_import_test.dart' as unnecessary_import;
797+
import 'unnecessary_nan_comparison_test.dart' as unnecessary_nan_comparison;
797798
import 'unnecessary_no_such_method_test.dart' as unnecessary_no_such_method;
798799
import 'unnecessary_non_null_assertion_test.dart'
799800
as unnecessary_non_null_assertion;
@@ -1362,6 +1363,7 @@ main() {
13621363
unnecessary_cast.main();
13631364
unnecessary_final.main();
13641365
unnecessary_ignore.main();
1366+
unnecessary_nan_comparison.main();
13651367
unnecessary_no_such_method.main();
13661368
unnecessary_non_null_assertion.main();
13671369
unnecessary_null_comparison.main();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) 2022, 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+
import 'package:analyzer/src/dart/error/hint_codes.dart';
6+
import 'package:test_reflective_loader/test_reflective_loader.dart';
7+
8+
import '../dart/resolution/context_collection_resolution.dart';
9+
10+
main() {
11+
defineReflectiveSuite(() {
12+
defineReflectiveTests(UnnecessaryNanComparisonTest);
13+
});
14+
}
15+
16+
@reflectiveTest
17+
class UnnecessaryNanComparisonTest extends PubPackageResolutionTest {
18+
test_equal() async {
19+
await assertErrorsInCode('''
20+
void f(double d) {
21+
d == double.nan;
22+
}
23+
''', [
24+
error(HintCode.UNNECESSARY_NAN_COMPARISON_FALSE, 23, 13),
25+
]);
26+
}
27+
28+
test_equal_nanFirst() async {
29+
await assertErrorsInCode('''
30+
void f(double d) {
31+
double.nan == d;
32+
}
33+
''', [
34+
error(HintCode.UNNECESSARY_NAN_COMPARISON_FALSE, 21, 13),
35+
]);
36+
}
37+
38+
test_notEqual() async {
39+
await assertErrorsInCode('''
40+
void f(double d) {
41+
d != double.nan;
42+
}
43+
''', [
44+
error(HintCode.UNNECESSARY_NAN_COMPARISON_TRUE, 23, 13),
45+
]);
46+
}
47+
48+
test_notEqual_nanFirst() async {
49+
await assertErrorsInCode('''
50+
void f(double d) {
51+
double.nan != d;
52+
}
53+
''', [
54+
error(HintCode.UNNECESSARY_NAN_COMPARISON_TRUE, 21, 13),
55+
]);
56+
}
57+
}

pkg/analyzer/tool/diagnostics/diagnostics.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19429,9 +19429,9 @@ class B extends A {}
1942919429

1943019430
### unnecessary_null_comparison
1943119431

19432-
_The operand can't be null, so the condition is always false._
19432+
_The operand can't be null, so the condition is always 'false'._
1943319433

19434-
_The operand can't be null, so the condition is always true._
19434+
_The operand can't be null, so the condition is always 'true'._
1943519435

1943619436
#### Description
1943719437

0 commit comments

Comments
 (0)