@@ -4,7 +4,7 @@ use oxc_macros::declare_oxc_lint;
44use oxc_span:: Span ;
55use oxc_syntax:: operator:: UnaryOperator ;
66
7- use crate :: { AstNode , context:: LintContext , rule:: Rule } ;
7+ use crate :: { AstNode , ast_util :: outermost_paren_parent , context:: LintContext , rule:: Rule } ;
88
99fn no_void_diagnostic ( span : Span ) -> OxcDiagnostic {
1010 OxcDiagnostic :: warn ( "Unexpected `void` operator" )
@@ -20,11 +20,12 @@ pub struct NoVoid {
2020declare_oxc_lint ! (
2121 /// ### What it does
2222 ///
23- /// Disallow `void` operators .
23+ /// Disallows the use of the `void` operator .
2424 ///
2525 /// Why is this bad
2626 ///
27- /// The `void` operator is often used to obtain the `undefined` primitive value, but it is unnecessary. You can use `undefined` directly instead.
27+ /// The `void` operator is often used to get `undefined`,
28+ /// but this is unnecessary because `undefined` can be used directly instead.
2829 ///
2930 /// ### Examples
3031 ///
@@ -40,10 +41,18 @@ declare_oxc_lint!(
4041 /// "foo.void()";
4142 /// "foo.void = bar";
4243 /// ```
44+ ///
45+ /// ### Options
46+ ///
47+ /// #### allowAsStatement
48+ ///
49+ /// `{ type: boolean, default: false }`
50+ ///
51+ /// If set to `true`, using `void` as a standalone statement is allowed.
4352 NoVoid ,
4453 eslint,
4554 restriction,
46- pending // TODO: suggestion
55+ suggestion
4756) ;
4857
4958impl Rule for NoVoid {
@@ -62,17 +71,16 @@ impl Rule for NoVoid {
6271 return ;
6372 } ;
6473
65- if let Some ( kind ) = ctx . nodes ( ) . parent_kind ( node. id ( ) ) {
66- if self . allow_as_statement && matches ! ( kind, AstKind :: ExpressionStatement ( _) ) {
74+ if let Some ( node ) = outermost_paren_parent ( node, ctx ) {
75+ if self . allow_as_statement && matches ! ( node . kind( ) , AstKind :: ExpressionStatement ( _) ) {
6776 return ;
6877 }
6978 }
7079
7180 if unary_expr. operator == UnaryOperator :: Void {
72- ctx. diagnostic ( no_void_diagnostic ( Span :: new (
73- unary_expr. span . start ,
74- unary_expr. span . start + 4 ,
75- ) ) ) ;
81+ ctx. diagnostic_with_suggestion ( no_void_diagnostic ( unary_expr. span ) , |fixer| {
82+ fixer. replace ( unary_expr. span , "undefined" )
83+ } ) ;
7684 }
7785 }
7886}
@@ -88,6 +96,7 @@ fn test() {
8896 ( "delete foo;" , None ) ,
8997 ( "void 0" , Some ( serde_json:: json!( [ { "allowAsStatement" : true } ] ) ) ) ,
9098 ( "void(0)" , Some ( serde_json:: json!( [ { "allowAsStatement" : true } ] ) ) ) ,
99+ ( "(void 0)" , Some ( serde_json:: json!( [ { "allowAsStatement" : true } ] ) ) ) ,
91100 ] ;
92101
93102 let fail = vec ! [
@@ -99,5 +108,18 @@ fn test() {
99108 ( "var foo = void 0" , Some ( serde_json:: json!( [ { "allowAsStatement" : true } ] ) ) ) ,
100109 ] ;
101110
102- Tester :: new ( NoVoid :: NAME , NoVoid :: PLUGIN , pass, fail) . test_and_snapshot ( ) ;
111+ let fix = vec ! [
112+ ( "void 0" , "undefined" , None ) ,
113+ ( "void 0" , "undefined" , Some ( serde_json:: json!( [ { } ] ) ) ) ,
114+ ( "void 0" , "undefined" , Some ( serde_json:: json!( [ { "allowAsStatement" : false } ] ) ) ) ,
115+ ( "void(0)" , "undefined" , None ) ,
116+ ( "var foo = void 0" , "var foo = undefined" , None ) ,
117+ (
118+ "var foo = void 0" ,
119+ "var foo = undefined" ,
120+ Some ( serde_json:: json!( [ { "allowAsStatement" : true } ] ) ) ,
121+ ) ,
122+ ] ;
123+
124+ Tester :: new ( NoVoid :: NAME , NoVoid :: PLUGIN , pass, fail) . expect_fix ( fix) . test_and_snapshot ( ) ;
103125}
0 commit comments