1
1
use oxc_ast:: {
2
2
AstKind ,
3
- ast:: { Argument , CallExpression , Expression } ,
3
+ ast:: { Argument , CallExpression , Expression , IdentifierReference } ,
4
4
} ;
5
5
use oxc_diagnostics:: OxcDiagnostic ;
6
6
use oxc_macros:: declare_oxc_lint;
7
- use oxc_semantic:: IsGlobalReference ;
8
7
use oxc_span:: { GetSpan , Span } ;
9
8
10
9
use crate :: { AstNode , context:: LintContext , rule:: Rule } ;
@@ -73,25 +72,23 @@ impl Rule for Radix {
73
72
} ;
74
73
75
74
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) ;
80
77
}
81
- Expression :: StaticMemberExpression ( member_expr) => {
78
+ Expression :: StaticMemberExpression ( member_expr)
79
+ if member_expr. property . name == "parseInt" =>
80
+ {
82
81
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) {
86
83
Self :: check_arguments ( self , call_expr, ctx) ;
87
84
}
88
85
}
89
86
}
90
87
Expression :: ChainExpression ( chain_expr) => {
91
88
if let Some ( member_expr) = chain_expr. expression . as_member_expression ( ) {
92
89
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 )
95
92
{
96
93
Self :: check_arguments ( self , call_expr, ctx) ;
97
94
}
@@ -104,6 +101,14 @@ impl Rule for Radix {
104
101
}
105
102
106
103
impl 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
+
107
112
fn check_arguments ( & self , call_expr : & CallExpression , ctx : & LintContext ) {
108
113
match call_expr. arguments . len ( ) {
109
114
0 => ctx. diagnostic ( missing_parameters ( call_expr. span ) ) ,
@@ -165,66 +170,74 @@ fn test() {
165
170
use crate :: tester:: Tester ;
166
171
167
172
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 ) ,
193
202
// ("/* 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 },
196
209
] ;
197
210
198
211
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 ) ,
228
241
] ;
229
242
230
243
Tester :: new ( Radix :: NAME , Radix :: PLUGIN , pass, fail) . test_and_snapshot ( ) ;
0 commit comments