diff --git a/crates/oxc_linter/src/rules/eslint/no_new_func.rs b/crates/oxc_linter/src/rules/eslint/no_new_func.rs index 85506339a6a3e..56b9e74ba9993 100644 --- a/crates/oxc_linter/src/rules/eslint/no_new_func.rs +++ b/crates/oxc_linter/src/rules/eslint/no_new_func.rs @@ -6,8 +6,22 @@ use oxc_span::{GetSpan, Ident, Span}; use crate::{AstNode, context::LintContext, rule::Rule}; -fn no_new_func(span: Span) -> OxcDiagnostic { - OxcDiagnostic::warn("The Function constructor is eval.").with_label(span) +fn no_new_func(function_call_span: Span, arguments_span: Option) -> OxcDiagnostic { + let mut diagnostic = OxcDiagnostic::warn("Using `new Function` or `Function` is not allowed.") + .with_help( + "Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function.", + ) + .with_note( + "The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain.", + ) + .with_label(function_call_span.primary_label("Dynamic function construction is used here.")); + + if let Some(arguments_span) = arguments_span { + diagnostic = diagnostic.and_label( + arguments_span.label("`Function` evaluates source text at runtime, similar to `eval`."), + ); + } + diagnostic } #[derive(Debug, Default, Clone)] @@ -53,14 +67,14 @@ impl Rule for NoNewFunc { return; }; - check(id, new_expr.span, ctx); + check(id, new_expr.arguments_span(), ctx); } AstKind::CallExpression(call_expr) => { let Some(obj_id) = call_expr.callee.get_identifier_reference() else { return; }; - check(obj_id, call_expr.span, ctx); + check(obj_id, call_expr.arguments_span(), ctx); } member_expr if member_expr.is_member_expression_kind() => { let Some(member_expr) = member_expr.as_member_expression_kind() else { @@ -96,16 +110,16 @@ impl Rule for NoNewFunc { return; }; - check(obj_id, parent_call_expr.span, ctx); + check(obj_id, parent_call_expr.arguments_span(), ctx); } _ => {} } } } -fn check(ident: &IdentifierReference, span: Span, ctx: &LintContext) { +fn check(ident: &IdentifierReference, arguments_span: Option, ctx: &LintContext) { if ident.is_global_reference_name(Ident::new_const("Function"), ctx.scoping()) { - ctx.diagnostic(no_new_func(span)); + ctx.diagnostic(no_new_func(ident.span, arguments_span)); } } diff --git a/crates/oxc_linter/src/snapshots/eslint_no_new_func.snap b/crates/oxc_linter/src/snapshots/eslint_no_new_func.snap index fd36038ee2a1e..a280f5dce3e83 100644 --- a/crates/oxc_linter/src/snapshots/eslint_no_new_func.snap +++ b/crates/oxc_linter/src/snapshots/eslint_no_new_func.snap @@ -2,62 +2,102 @@ source: crates/oxc_linter/src/tester.rs --- - ⚠ eslint(no-new-func): The Function constructor is eval. - ╭─[no_new_func.tsx:1:9] + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. + ╭─[no_new_func.tsx:1:13] 1 │ var a = new Function("b", "c", "return b+c"); - · ──────────────────────────────────── + · ────┬─── ───────────┬────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. ╭─[no_new_func.tsx:1:9] 1 │ var a = Function("b", "c", "return b+c"); - · ──────────────────────────────── + · ────┬─── ───────────┬────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. ╭─[no_new_func.tsx:1:9] 1 │ var a = Function.call(null, "b", "c", "return b+c"); - · ─────────────────────────────────────────── + · ────┬─── ──────────────┬───────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. ╭─[no_new_func.tsx:1:9] 1 │ var a = Function.apply(null, ["b", "c", "return b+c"]); - · ────────────────────────────────────────────── + · ────┬─── ───────────────┬────────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. ╭─[no_new_func.tsx:1:9] 1 │ var a = Function.bind(null, "b", "c", "return b+c")(); - · ─────────────────────────────────────────── + · ────┬─── ──────────────┬───────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. ╭─[no_new_func.tsx:1:9] 1 │ var a = Function.bind(null, "b", "c", "return b+c"); - · ─────────────────────────────────────────── + · ────┬─── ──────────────┬───────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. ╭─[no_new_func.tsx:1:9] 1 │ var a = Function["call"](null, "b", "c", "return b+c"); - · ────────────────────────────────────────────── + · ────┬─── ──────────────┬───────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. - ╭─[no_new_func.tsx:1:9] + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. + ╭─[no_new_func.tsx:1:10] 1 │ var a = (Function?.call)(null, "b", "c", "return b+c"); - · ────────────────────────────────────────────── + · ────┬─── ──────────────┬───────────── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. - ╭─[no_new_func.tsx:1:41] + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. + ╭─[no_new_func.tsx:1:45] 1 │ const fn = () => { class Function {} }; new Function('', '') - · ──────────────────── + · ────┬─── ───┬── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain. - ⚠ eslint(no-new-func): The Function constructor is eval. + ⚠ eslint(no-new-func): Using `new Function` or `Function` is not allowed. ╭─[no_new_func.tsx:1:50] 1 │ var fn = function () { function Function() {} }; Function('', '') - · ──────────────── + · ────┬─── ───┬── + · │ ╰── `Function` evaluates source text at runtime, similar to `eval`. + · ╰── Dynamic function construction is used here. ╰──── + help: Avoid the `Function` constructor. Define the function directly with a function declaration/expression or an arrow function. + note: The `Function` constructor compiles code from strings at runtime, which can introduce injection risks, hurts performance, and makes code harder to analyze and maintain.