Skip to content

OD602 orphan-patch-super

A patch calls a super method the class it patches does not have.

Category Severity Series Needs the index
Correctness Error 17.0 and later yes

What it reports

A super.name() call in a method of patch(Class.prototype, {...}) when neither the class nor any class it extends has a method, accessor or field name, and no other patch of those classes adds one. The class is followed through imports and re-exports to the file that declares it. Owl's Component counts as having setup and render.

Why it matters

patch makes super in the patch's methods point at the class's own member, or the previous patch's. When there is none, super.name is undefined and the call throws a TypeError the first time the patched method runs. The usual cause is a method renamed or removed upstream between series: the override no longer overrides anything, and it breaks as soon as it is called.

The rule stays silent when it cannot see every parent: a class extending an expression such as a mixin call, or a class from a module that is not indexed or not a script, such as an Owl class other than Component, and a module whose dependencies include one that is not indexed (such as an Enterprise module, which may patch the class too). A read such as super.name || fallback is not reported, since it tolerates a missing member. Before 17.0, a patch reached the patched method through this._super, which the rule does not read.

Example

static/src/js/form_controller_patch.js
import { patch } from "@web/core/utils/patch";
import { FormController } from "@web/views/form/form_controller";

patch(FormController.prototype, {
    async onRecordSave(record, changes) {
        await super.onRecordSave(...arguments);
        this.notification.add("Saved");
    },
});

FormController names this method onRecordSaved, so the patch adds a method nobody calls, and calling it fails.

static/src/js/form_controller_patch.js
import { patch } from "@web/core/utils/patch";
import { FormController } from "@web/views/form/form_controller";

patch(FormController.prototype, {
    async onRecordSaved(record, changes) {
        await super.onRecordSaved(...arguments);
        this.notification.add("Saved");
    },
});

Suppressing

await super.onRecordSave(...arguments); // odooscan: ignore[OD602]

See suppressing a finding.