oxc-project/oxc · warning · OxcDiagnostic

Avoid unnecessary use of .{name}()

Error message

Avoid unnecessary use of .{name}()

What it means

Diagnostic from the `no-useless-call` rule. It fires when `.call()` or `.apply()` adds nothing: the thisArg is null/undefined (or identical to the callee receiver) and apply's argument array is a plain spread of the same arguments a direct call would take. In strict-mode ES modules `this` is already undefined, so the indirection is pure overhead. Oxc detects it via `match_member_expression` on CallExpression whose callee property is `call`/`apply` on a plain function.

Source

Thrown at crates/oxc_linter/src/rules/eslint/no_useless_call.rs:14

use oxc_ast::{
    AstKind,
    ast::{CallExpression, ChainElement, Expression, MemberExpression},
    match_member_expression,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::ContentEq;
use oxc_span::Span;

use crate::{AstNode, context::LintContext, rule::Rule};

fn no_useless_call_diagnostic(name: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("Avoid unnecessary use of .{name}()"))
        .with_help("Replace with a normal function invocation")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct NoUselessCall;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow unnecessary calls to `.call()` and `.apply()`
    ///
    /// ### Why is this bad?
    ///
    /// `Function.prototype.call()` and `Function.prototype.apply()` are slower than the normal function invocation.
    ///
    /// This rule compares code statically to check whether or not thisArg is changed.
    /// So if the code about thisArg is a dynamic expression, this rule cannot judge correctly.

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Replace `foo.call(null, 1, 2)` with a direct call `foo(1, 2)`.
  2. Replace `foo.apply(null, args)` with `foo(...args)`.
  3. If you rely on `this` binding, pass a meaningful thisArg or use `fn.bind(receiver)` once.
  4. Fix is often automatic: run `oxlint --fix` to rewrite the call.

Example fix

// before
foo.call(null, 1, 2);
foo.apply(undefined, [1, 2]);

// after
foo(1, 2);
foo(1, 2);
Defensive patterns

Strategy: validation

Validate before calling

function isUselessCall(node) {
  // before refactoring, detect .call(null/undefined, ...) patterns in review
  return /^\.call\((null|undefined)/.test(snippet) || /^\.apply\((null|undefined),\s*\[/.test(snippet);
}

Prevention

When it happens

Trigger: Calls like `foo.call(null)`, `foo.call(undefined, 1)`, `foo.apply(this, arguments)` in non-method contexts, or `obj.fn.call(obj, ...)` where the receiver equals the object itself. The rule matches MemberExpression callees named call/apply whose arguments provide no binding effect.

Common situations: Code ported from ES5 libraries that needed apply for variadic args before spread syntax; defensive `this` binding habits; bundled output from old transpilers that was hand-edited.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/01c8baaf06d06e1f. Report an issue: GitHub.