Repository: eslint/eslint
File: lib/rules/no-useless-assignment.js (JavaScript)

Code before:
            }

            /**
             * Verifies whether the given assignment info is an used assignment.
             * Report if it is an unused assignment.
             * @param {AssignmentInfo} targetAssignment The assignment info to verify.
             * @param {AssignmentInfo[]} allAssignments The list of all assignment info for variables.
             * @returns {void}
             */
            function verifyAssignmentIsUsed(targetAssignment, allAssignments) {

                // Skip if the variable is assigned in the try block.
                const isAssignedInTryBlock = targetAssignment.variable.references.some(reference => {
                    const id = reference.identifier;

                    if (id.parent.type === "AssignmentExpression") {
                        return target.tryStatementBlocks.some(tryBlock =>
                            tryBlock.range[0] <= id.range[0] && id.range[1] <= tryBlock.range[1]);
                    }

                    return false;
                });

                if (isAssignedInTryBlock) {
                    return;
                }

                /**
                 * @typedef {Object} SubsequentSegmentData
                 * @property {CodePathSegment} segment The code path segment
                 * @property {AssignmentInfo} [assignment] The first occurrence of the assignment within the segment.
                 * There is no need to check if the variable is used after this assignment,
                 * as the value it was assigned will be used.
                 */

                /**
                 * Information used in `getSubsequentSegments()`.
                 * To avoid unnecessary iterations, cache information that has already been iterated over,
                 * and if additional iterations are needed, start iterating from the retained position.
                 */
                const subsequentSegmentData = {

                    /**
                     * Cache of subsequent segment information list that have already been iterated.
                     * @type {SubsequentSegmentData[]}
                     */
                    results: [],

                    /**
                     * Subsequent segments that have already been iterated on. Used to avoid infinite loops.
                     * @type {Set<CodePathSegment>}

Review comment (suggestion):
Instead of entirely ignoring a variable if it has an assignment in a try block, can we just ignore that assignment (i.e., skip checking `targetAssignment` if it's in a try block)? I think that would restore now-removed `invalid` test cases.

Code after:
            }

            /**
             * Verifies whether the given assignment info is an used assignment.
             * Report if it is an unused assignment.
             * @param {AssignmentInfo} targetAssignment The assignment info to verify.
             * @param {AssignmentInfo[]} allAssignments The list of all assignment info for variables.
             * @returns {void}
             */
            function verifyAssignmentIsUsed(targetAssignment, allAssignments) {

                // Skip assignment if it is in a try block.
                const isAssignmentInTryBlock = target.tryStatementBlocks.some(tryBlock =>
                    tryBlock.range[0] <= targetAssignment.identifier.range[0] &&
                    targetAssignment.identifier.range[1] <= tryBlock.range[1]
                );

                if (isAssignmentInTryBlock) {
                    return;
                }

                /**
                 * @typedef {Object} SubsequentSegmentData
                 * @property {CodePathSegment} segment The code path segment
                 * @property {AssignmentInfo} [assignment] The first occurrence of the assignment within the segment.
                 * There is no need to check if the variable is used after this assignment,
                 * as the value it was assigned will be used.
                 */

                /**
                 * Information used in `getSubsequentSegments()`.
                 * To avoid unnecessary iterations, cache information that has already been iterated over,
                 * and if additional iterations are needed, start iterating from the retained position.
                 */
                const subsequentSegmentData = {

                    /**
                     * Cache of subsequent segment information list that have already been iterated.
                     * @type {SubsequentSegmentData[]}
                     */
                    results: [],

                    /**
                     * Subsequent segments that have already been iterated on. Used to avoid infinite loops.
                     * @type {Set<CodePathSegment>}
                     */
                    subsequentSegments: new Set(),

                    /**
                     * Unexplored code path segment.
                     * If additional iterations are needed, consume this information and iterate.