@@ -5,6 +5,7 @@ use oxc_ast::{
55use oxc_diagnostics:: OxcDiagnostic ;
66use oxc_macros:: declare_oxc_lint;
77use oxc_span:: Span ;
8+ use oxc_syntax:: operator:: { AssignmentOperator , BinaryOperator } ;
89
910use crate :: { context:: LintContext , rule:: Rule , AstNode } ;
1011
@@ -37,14 +38,22 @@ fn not_need_no_confusing_non_null_assertion_diagnostic(op_str: &str, span: Span)
3738 . with_label ( span)
3839}
3940
40- fn wrap_up_no_confusing_non_null_assertion_diagnostic ( span : Span ) -> OxcDiagnostic {
41- OxcDiagnostic :: warn (
42- "Confusing combinations of non-null assertion and equal test like \" a! = b\" , which looks very similar to not equal \" a != b\" ."
43- )
41+ fn wrap_up_no_confusing_non_null_assertion_diagnostic ( op_str : & str , span : Span ) -> OxcDiagnostic {
42+ OxcDiagnostic :: warn ( format ! (
43+ "Confusing combinations of non-null assertion and equal test like \" a! {op_str} b\" , which looks very similar to not equal \" a !{op_str} b\" ."
44+ ) )
4445 . with_help ( "Wrap left-hand side in parentheses to avoid putting non-null assertion \" !\" and \" =\" together." )
4546 . with_label ( span)
4647}
4748
49+ fn confusing_non_null_assignment_assertion_diagnostic ( op_str : & str , span : Span ) -> OxcDiagnostic {
50+ OxcDiagnostic :: warn ( format ! (
51+ "Confusing combinations of non-null assertion and assignment like \" a! {op_str} b\" , which looks very similar to not equal \" a !{op_str} b\" ."
52+ ) )
53+ . with_help ( "Remove the \" !\" , or wrap the left-hand side in parentheses." )
54+ . with_label ( span)
55+ }
56+
4857fn get_depth_ends_in_bang ( expr : & Expression < ' _ > ) -> Option < u32 > {
4958 match expr {
5059 Expression :: TSNonNullExpression ( _) => Some ( 0 ) ,
@@ -61,10 +70,16 @@ fn get_depth_ends_in_bang(expr: &Expression<'_>) -> Option<u32> {
6170 }
6271}
6372
73+ fn is_confusable_operator ( operator : BinaryOperator ) -> bool {
74+ matches ! ( operator, BinaryOperator :: Equality | BinaryOperator :: StrictEquality )
75+ }
76+
6477impl Rule for NoConfusingNonNullAssertion {
6578 fn run < ' a > ( & self , node : & AstNode < ' a > , ctx : & LintContext < ' a > ) {
6679 match node. kind ( ) {
67- AstKind :: BinaryExpression ( binary_expr) => {
80+ AstKind :: BinaryExpression ( binary_expr)
81+ if is_confusable_operator ( binary_expr. operator ) =>
82+ {
6883 let Some ( bang_depth) = get_depth_ends_in_bang ( & binary_expr. left ) else {
6984 return ;
7085 } ;
@@ -75,16 +90,19 @@ impl Rule for NoConfusingNonNullAssertion {
7590 ) ) ;
7691 } else {
7792 ctx. diagnostic ( wrap_up_no_confusing_non_null_assertion_diagnostic (
93+ binary_expr. operator . as_str ( ) ,
7894 binary_expr. span ,
7995 ) ) ;
8096 }
8197 }
82- AstKind :: AssignmentExpression ( assignment_expr) => {
98+ AstKind :: AssignmentExpression ( assignment_expr)
99+ if assignment_expr. operator == AssignmentOperator :: Assign =>
100+ {
83101 let Some ( simple_target) = assignment_expr. left . as_simple_assignment_target ( ) else {
84102 return ;
85103 } ;
86104 let SimpleAssignmentTarget :: TSNonNullExpression ( _) = simple_target else { return } ;
87- ctx. diagnostic ( not_need_no_confusing_non_null_assertion_diagnostic (
105+ ctx. diagnostic ( confusing_non_null_assignment_assertion_diagnostic (
88106 assignment_expr. operator . as_str ( ) ,
89107 assignment_expr. span ,
90108 ) ) ;
@@ -102,7 +120,25 @@ impl Rule for NoConfusingNonNullAssertion {
102120fn test ( ) {
103121 use crate :: tester:: Tester ;
104122
105- let pass = vec ! [ "a == b!;" , "a = b!;" , "a !== b;" , "a != b;" , "(a + b!) == c;" ] ; // "(a + b!) = c;"]; that's a parse error??
123+ let pass = vec ! [
124+ "a == b!;" ,
125+ "a = b!;" ,
126+ "a !== b;" ,
127+ "a != b;" ,
128+ "(a + b!) == c;" ,
129+ "a! + b;" ,
130+ "a! += b;" ,
131+ "a! - b;" ,
132+ "a! -= b;" ,
133+ "a! / b;" ,
134+ "a! /= b;" ,
135+ "a! * b;" ,
136+ "a! *= b;" ,
137+ "a! ** b;" ,
138+ "a! **= b;" ,
139+ "a! != b;" ,
140+ "a! !== b;" ,
141+ ] ;
106142 let fail = vec ! [
107143 "a! == b;" ,
108144 "a! === b;" ,
0 commit comments