11use oxc_ast:: {
22 AstKind ,
3- ast:: { Argument , CallExpression , Expression } ,
3+ ast:: { Argument , CallExpression , Expression , IdentifierReference } ,
44} ;
55use oxc_diagnostics:: OxcDiagnostic ;
66use oxc_macros:: declare_oxc_lint;
7- use oxc_semantic:: IsGlobalReference ;
87use oxc_span:: { GetSpan , Span } ;
98
109use crate :: { AstNode , context:: LintContext , rule:: Rule } ;
@@ -73,25 +72,23 @@ impl Rule for Radix {
7372 } ;
7473
7574 match call_expr. callee . without_parentheses ( ) {
76- Expression :: Identifier ( ident) => {
77- if ident. is_global_reference_name ( "parseInt" , ctx. symbols ( ) ) {
78- Self :: check_arguments ( self , call_expr, ctx) ;
79- }
75+ Expression :: Identifier ( ident) if Self :: is_global_parse_int_ident ( ident, ctx) => {
76+ Self :: check_arguments ( self , call_expr, ctx) ;
8077 }
81- Expression :: StaticMemberExpression ( member_expr) => {
78+ Expression :: StaticMemberExpression ( member_expr)
79+ if member_expr. property . name == "parseInt" =>
80+ {
8281 if let Expression :: Identifier ( ident) = member_expr. object . without_parentheses ( ) {
83- if ident. is_global_reference_name ( "Number" , ctx. symbols ( ) )
84- && member_expr. property . name == "parseInt"
85- {
82+ if Self :: is_global_number_ident ( ident, ctx) {
8683 Self :: check_arguments ( self , call_expr, ctx) ;
8784 }
8885 }
8986 }
9087 Expression :: ChainExpression ( chain_expr) => {
9188 if let Some ( member_expr) = chain_expr. expression . as_member_expression ( ) {
9289 if let Expression :: Identifier ( ident) = member_expr. object ( ) {
93- if ident . is_global_reference_name ( "Number" , ctx . symbols ( ) )
94- && member_expr . static_property_name ( ) == Some ( "parseInt" )
90+ if member_expr . static_property_name ( ) == Some ( "parseInt" )
91+ && Self :: is_global_number_ident ( ident , ctx )
9592 {
9693 Self :: check_arguments ( self , call_expr, ctx) ;
9794 }
@@ -104,6 +101,14 @@ impl Rule for Radix {
104101}
105102
106103impl Radix {
104+ fn is_global_number_ident ( ident : & IdentifierReference , ctx : & LintContext ) -> bool {
105+ ident. name == "Number" && ctx. is_reference_to_global_variable ( ident)
106+ }
107+
108+ fn is_global_parse_int_ident ( ident : & IdentifierReference , ctx : & LintContext ) -> bool {
109+ ident. name == "parseInt" && ctx. is_reference_to_global_variable ( ident)
110+ }
111+
107112 fn check_arguments ( & self , call_expr : & CallExpression , ctx : & LintContext ) {
108113 match call_expr. arguments . len ( ) {
109114 0 => ctx. diagnostic ( missing_parameters ( call_expr. span ) ) ,
@@ -165,66 +170,74 @@ fn test() {
165170 use crate :: tester:: Tester ;
166171
167172 let pass = vec ! [
168- ( r#"parseInt("10", 10);"# , None ) ,
169- ( r#"parseInt("10", 2);"# , None ) ,
170- ( r#"parseInt("10", 36);"# , None ) ,
171- ( r#"parseInt("10", 0x10);"# , None ) ,
172- ( r#"parseInt("10", 1.6e1);"# , None ) ,
173- ( r#"parseInt("10", 10.0);"# , None ) ,
174- ( r#"parseInt("10", foo);"# , None ) ,
175- ( r#"Number.parseInt("10", foo);"# , None ) ,
176- ( r#"parseInt("10", 10);"# , Some ( json!( [ "always" ] ) ) ) ,
177- ( r#"parseInt("10");"# , Some ( json!( [ "as-needed" ] ) ) ) ,
178- ( r#"parseInt("10", 8);"# , Some ( json!( [ "as-needed" ] ) ) ) ,
179- ( r#"parseInt("10", foo);"# , Some ( json!( [ "as-needed" ] ) ) ) ,
180- ( "parseInt" , None ) ,
181- ( "Number.foo();" , None ) ,
182- ( "Number[parseInt]();" , None ) ,
183- ( "class C { #parseInt; foo() { Number.#parseInt(); } }" , None ) ,
184- ( "class C { #parseInt; foo() { Number.#parseInt(foo); } }" , None ) ,
185- ( "class C { #parseInt; foo() { Number.#parseInt(foo, 'bar'); } }" , None ) ,
186- ( "class C { #parseInt; foo() { Number.#parseInt(foo, 10); } }" , Some ( json!( [ "as-needed" ] ) ) ) ,
187- ( "var parseInt; parseInt();" , None ) ,
188- ( "var parseInt; parseInt(foo);" , Some ( json!( [ "always" ] ) ) ) ,
189- ( "var parseInt; parseInt(foo, 10);" , Some ( json!( [ "as-needed" ] ) ) ) ,
190- ( "var Number; Number.parseInt();" , None ) ,
191- ( "var Number; Number.parseInt(foo);" , Some ( json!( [ "always" ] ) ) ) ,
192- ( "var Number; Number.parseInt(foo, 10);" , Some ( json!( [ "as-needed" ] ) ) ) ,
173+ ( r#"parseInt("10", 10);"# , None , None ) ,
174+ ( r#"parseInt("10", 2);"# , None , None ) ,
175+ ( r#"parseInt("10", 36);"# , None , None ) ,
176+ ( r#"parseInt("10", 0x10);"# , None , None ) ,
177+ ( r#"parseInt("10", 1.6e1);"# , None , None ) ,
178+ ( r#"parseInt("10", 10.0);"# , None , None ) ,
179+ ( r#"parseInt("10", foo);"# , None , None ) ,
180+ ( r#"Number.parseInt("10", foo);"# , None , None ) ,
181+ ( r#"parseInt("10", 10);"# , Some ( json!( [ "always" ] ) ) , None ) ,
182+ ( r#"parseInt("10");"# , Some ( json!( [ "as-needed" ] ) ) , None ) ,
183+ ( r#"parseInt("10", 8);"# , Some ( json!( [ "as-needed" ] ) ) , None ) ,
184+ ( r#"parseInt("10", foo);"# , Some ( json!( [ "as-needed" ] ) ) , None ) ,
185+ ( "parseInt" , None , None ) ,
186+ ( "Number.foo();" , None , None ) ,
187+ ( "Number[parseInt]();" , None , None ) ,
188+ ( "class C { #parseInt; foo() { Number.#parseInt(); } }" , None , None ) ,
189+ ( "class C { #parseInt; foo() { Number.#parseInt(foo); } }" , None , None ) ,
190+ ( "class C { #parseInt; foo() { Number.#parseInt(foo, 'bar'); } }" , None , None ) ,
191+ (
192+ "class C { #parseInt; foo() { Number.#parseInt(foo, 10); } }" ,
193+ Some ( json!( [ "as-needed" ] ) ) ,
194+ None ,
195+ ) ,
196+ ( "var parseInt; parseInt();" , None , None ) ,
197+ ( "var parseInt; parseInt(foo);" , Some ( json!( [ "always" ] ) ) , None ) ,
198+ ( "var parseInt; parseInt(foo, 10);" , Some ( json!( [ "as-needed" ] ) ) , None ) ,
199+ ( "var Number; Number.parseInt();" , None , None ) ,
200+ ( "var Number; Number.parseInt(foo);" , Some ( json!( [ "always" ] ) ) , None ) ,
201+ ( "var Number; Number.parseInt(foo, 10);" , Some ( json!( [ "as-needed" ] ) ) , None ) ,
193202 // ("/* globals parseInt:off */ parseInt(foo);", Some(json!(["always"]))),
194- // ("Number.parseInt(foo, 10);", Some(json!(["as-needed"]))), // { globals: { Number: "off" } }
195- ( r#"function *f(){ yield(Number).parseInt("10", foo) }"# , None ) , // { "ecmaVersion": 6 },
203+ (
204+ "Number.parseInt(foo, 10);" ,
205+ Some ( json!( [ "as-needed" ] ) ) ,
206+ Some ( serde_json:: json!( { "globals" : { "Number" : "off" } } ) ) ,
207+ ) ,
208+ ( r#"function *f(){ yield(Number).parseInt("10", foo) }"# , None , None ) , // { "ecmaVersion": 6 },
196209 ] ;
197210
198211 let fail = vec ! [
199- ( "parseInt();" , Some ( json!( [ "as-needed" ] ) ) ) ,
200- ( "parseInt();" , None ) ,
201- ( r#"parseInt("10");"# , None ) ,
202- ( r#"parseInt("10",);"# , None ) ,
203- ( r#"parseInt((0, "10"));"# , None ) ,
204- ( r#"parseInt((0, "10"),);"# , None ) ,
205- ( r#"parseInt("10", null);"# , None ) ,
206- ( r#"parseInt("10", undefined);"# , None ) ,
207- ( r#"parseInt("10", true);"# , None ) ,
208- ( r#"parseInt("10", "foo");"# , None ) ,
209- ( r#"parseInt("10", "123");"# , None ) ,
210- ( r#"parseInt("10", 1);"# , None ) ,
211- ( r#"parseInt("10", 37);"# , None ) ,
212- ( r#"parseInt("10", 10.5);"# , None ) ,
213- ( "Number.parseInt();" , None ) ,
214- ( "Number.parseInt();" , Some ( json!( [ "as-needed" ] ) ) ) ,
215- ( r#"Number.parseInt("10");"# , None ) ,
216- ( r#"Number.parseInt("10", 1);"# , None ) ,
217- ( r#"Number.parseInt("10", 37);"# , None ) ,
218- ( r#"Number.parseInt("10", 10.5);"# , None ) ,
219- ( r#"parseInt("10", 10);"# , Some ( json!( [ "as-needed" ] ) ) ) ,
220- ( r#"parseInt?.("10");"# , None ) ,
221- ( r#"Number.parseInt?.("10");"# , None ) ,
222- ( r#"Number?.parseInt("10");"# , None ) ,
223- ( r#"(Number?.parseInt)("10");"# , None ) ,
224- ( "function *f(){ yield(Number).parseInt() }" , None ) , // { "ecmaVersion": 6 },
225- ( "{ let parseInt; } parseInt();" , None ) ,
226- ( "{ let Number; } Number.parseInt();" , None ) ,
227- ( "{ let Number; } (Number?.parseInt)();" , None ) ,
212+ ( "parseInt();" , Some ( json!( [ "as-needed" ] ) ) , None ) ,
213+ ( "parseInt();" , None , None ) ,
214+ ( r#"parseInt("10");"# , None , None ) ,
215+ ( r#"parseInt("10",);"# , None , None ) ,
216+ ( r#"parseInt((0, "10"));"# , None , None ) ,
217+ ( r#"parseInt((0, "10"),);"# , None , None ) ,
218+ ( r#"parseInt("10", null);"# , None , None ) ,
219+ ( r#"parseInt("10", undefined);"# , None , None ) ,
220+ ( r#"parseInt("10", true);"# , None , None ) ,
221+ ( r#"parseInt("10", "foo");"# , None , None ) ,
222+ ( r#"parseInt("10", "123");"# , None , None ) ,
223+ ( r#"parseInt("10", 1);"# , None , None ) ,
224+ ( r#"parseInt("10", 37);"# , None , None ) ,
225+ ( r#"parseInt("10", 10.5);"# , None , None ) ,
226+ ( "Number.parseInt();" , None , None ) ,
227+ ( "Number.parseInt();" , Some ( json!( [ "as-needed" ] ) ) , None ) ,
228+ ( r#"Number.parseInt("10");"# , None , None ) ,
229+ ( r#"Number.parseInt("10", 1);"# , None , None ) ,
230+ ( r#"Number.parseInt("10", 37);"# , None , None ) ,
231+ ( r#"Number.parseInt("10", 10.5);"# , None , None ) ,
232+ ( r#"parseInt("10", 10);"# , Some ( json!( [ "as-needed" ] ) ) , None ) ,
233+ ( r#"parseInt?.("10");"# , None , None ) ,
234+ ( r#"Number.parseInt?.("10");"# , None , None ) ,
235+ ( r#"Number?.parseInt("10");"# , None , None ) ,
236+ ( r#"(Number?.parseInt)("10");"# , None , None ) ,
237+ ( "function *f(){ yield(Number).parseInt() }" , None , None ) , // { "ecmaVersion": 6 },
238+ ( "{ let parseInt; } parseInt();" , None , None ) ,
239+ ( "{ let Number; } Number.parseInt();" , None , None ) ,
240+ ( "{ let Number; } (Number?.parseInt)();" , None , None ) ,
228241 ] ;
229242
230243 Tester :: new ( Radix :: NAME , Radix :: PLUGIN , pass, fail) . test_and_snapshot ( ) ;
0 commit comments