Repository: eslint/eslint
File: lib/rules/no-unused-vars.js (JavaScript)

Code before:
                    if (!config.reportUsedIgnorePattern && variable.eslintUsed) {
                        continue;
                    }

                    // skip implicit "arguments" variable
                    if (scope.type === "function" && variable.name === "arguments" && variable.identifiers.length === 0) {
                        continue;
                    }

                    // explicit global variables don't have definitions.
                    const def = variable.defs[0];

                    if (def) {
                        const type = def.type;
                        const refUsedInArrayPatterns = variable.references.some(ref => ref.identifier.parent.type === "ArrayPattern");

                        // skip elements of array destructuring patterns
                        if (
                            (
                                def.name.parent.type === "ArrayPattern" ||
                                refUsedInArrayPatterns
                            ) &&
                            config.destructuredArrayIgnorePattern &&
                            config.destructuredArrayIgnorePattern.test(def.name.name)
                        ) {
                            if (config.reportUsedIgnorePattern && (variable.eslintUsed || isUsedVariable(variable))) {
                                usedIgnoredVars.push(variable);
                            }

                            continue;
                        }

                        // skip catch variables
                        if (type === "CatchClause") {
                            if (config.caughtErrors === "none") {
                                continue;
                            }

                            // skip ignored parameters
                            if (config.caughtErrorsIgnorePattern && config.caughtErrorsIgnorePattern.test(def.name.name)) {
                                if (config.reportUsedIgnorePattern && (variable.eslintUsed || isUsedVariable(variable))) {
                                    usedIgnoredVars.push(variable);
                                }

                                continue;
                            }
                        } else if (type === "Parameter") {

                            // skip any setter argument
                            if ((def.node.parent.type === "Property" || def.node.parent.type === "MethodDefinition") && def.node.parent.kind === "set") {
                                continue;

Review comment (refactor):
It looks like we are doing `variable.eslintUsed || isUsedVariable(variable)` multiple times. It seems like we should move the check of `variable.eslintUsed` into the `isUsedVariable()` function to simplify the rest of the code.

Code after:

            let rhsNode = null;

            return variable.references.some(ref => {
                if (isForInOfRef(ref)) {
                    return true;
                }

                const forItself = isReadForItself(ref, rhsNode);

                rhsNode = getRhsNode(ref, rhsNode);

                return (
                    isReadRef(ref) &&
                    !forItself &&
                    !(isFunctionDefinition && isSelfReference(ref, functionNodes))
                );
            });
        }

        /**
         * Checks whether the given variable is after the last used parameter.
         * @param {eslint-scope.Variable} variable The variable to check.
         * @returns {boolean} `true` if the variable is defined after the last
         * used parameter.
         */
        function isAfterLastUsedArg(variable) {
            const def = variable.defs[0];
            const params = sourceCode.getDeclaredVariables(def.node);
            const posteriorParams = params.slice(params.indexOf(variable) + 1);

            // If any used parameters occur after this parameter, do not report.
            return !posteriorParams.some(v => v.references.length > 0 || v.eslintUsed);
        }

        /**
         * Gets an array of variables without read references.
         * @param {Scope} scope an eslint-scope Scope object.
         * @param {Variable[]} unusedVars an array that saving result.
         * @returns {Variable[]} unused variables of the scope and descendant scopes.
         * @private
         */
        function collectUnusedVariables(scope, unusedVars) {
            const variables = scope.variables;
            const childScopes = scope.childScopes;
            let i, l;

            if (scope.type !== "global" || config.vars === "all") {
                for (i = 0, l = variables.length; i < l; ++i) {
                    const variable = variables[i];