Repository: eslint/eslint
File: lib/rules/no-prototype-builtins.js (JavaScript)

Code before:
            if (propName !== null && DISALLOWED_PROPS.has(propName)) {
                context.report({
                    messageId: "prototypeBuildIn",
                    loc: callee.property.loc,
                    data: { prop: propName },
                    node,
                    suggest: [
                        {
                            messageId: "callObjectPrototype",
                            data: { prop: propName },
                            fix(fixer) {

                                /*
                                 * a call after an optional chain (e.g. a?.b.hasOwnProperty(c))
                                 * must be fixed manually because the call can be short-circuited
                                 */
                                if (isAfterOptional(node)) {
                                    return null;
                                }

                                const sourceCode = context.sourceCode;
                                const openParenToken = sourceCode.getTokenAfter(
                                    node.callee,
                                    astUtils.isOpeningParenToken
                                );
                                const objectText = sourceCode.getText(callee.object);
                                const isEmptyParameters = node.arguments.length === 0;
                                const delim = isEmptyParameters ? "" : ", ";
                                const fixes = [
                                    fixer.replaceText(callee, `Object.prototype.${propName}.call`),
                                    fixer.insertTextAfter(openParenToken, objectText + delim)
                                ];

                                return fixes;
                            }
                        }
                    ]
                });
            }
        }

        return {
            CallExpression: disallowBuiltIns
        };
    }
};


Review comment (suggestion):
If `callee.object` is a SequenceExpression, we need to parenthesize it in arguments.

```js
// should be Object.prototype.hasOwnProperty.call((a, b), 'bar');
// instead of Object.prototype.hasOwnProperty.call(a, b, 'bar');
(a, b).hasOwnProperty('bar');
```

Code after:
            if (propName !== null && DISALLOWED_PROPS.has(propName)) {
                context.report({
                    messageId: "prototypeBuildIn",
                    loc: callee.property.loc,
                    data: { prop: propName },
                    node,
                    suggest: [
                        {
                            messageId: "callObjectPrototype",
                            data: { prop: propName },
                            fix(fixer) {
                                const sourceCode = context.sourceCode;

                                /*
                                 * A call after an optional chain (e.g. a?.b.hasOwnProperty(c))
                                 * must be fixed manually because the call can be short-circuited
                                 */
                                if (isAfterOptional(node)) {
                                    return null;
                                }

                                /*
                                 * A call on a ChainExpression (e.g. (a?.hasOwnProperty)(c)) will trigger
                                 * no-unsafe-optional-chaining which should be fixed before this suggestion
                                 */
                                if (node.callee.type === "ChainExpression") {
                                    return null;
                                }

                                const objectVariable = astUtils.getVariableByName(sourceCode.getScope(node), "Object");

                                /*
                                 * We can't use Object if the global Object was shadowed,
                                 * or Object does not exist in the global scope for some reason
                                 */
                                if (!objectVariable || objectVariable.scope.type !== "global" || objectVariable.defs.length > 0) {
                                    return null;
                                }

                                let objectText = sourceCode.getText(callee.object);

                                if (astUtils.getPrecedence(callee.object) <= astUtils.getPrecedence({ type: "SequenceExpression" })) {
                                    objectText = `(${objectText})`;
                                }

                                const openParenToken = sourceCode.getTokenAfter(
                                    node.callee,
                                    astUtils.isOpeningParenToken
                                );
                                const isEmptyParameters = node.arguments.length === 0;
                                const delim = isEmptyParameters ? "" : ", ";