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

Code before:
                    .filter(prevSegment => !usedUnreachableSegments.has(prevSegment))
                    .forEach(markReturnStatementsOnSegmentAsUsed);
                return;
            }

            const info = segmentInfoMap.get(segment);

            for (const node of info.uselessReturns) {
                if (scopeInfo.traversedTryBlockStatements && scopeInfo.traversedTryBlockStatements.length > 0) {
                    const blockInitialRange = scopeInfo.traversedTryBlockStatements[0].range[0];
                    const blockFinalRange = scopeInfo.traversedTryBlockStatements[0].range[1];
                    const returnInitialRange = node.range[0];
                    const returnFinalRange = node.range[1];

                    if (returnInitialRange >= blockInitialRange && returnFinalRange <= blockFinalRange) {
                        continue;
                    }
                }

                remove(scopeInfo.uselessReturns, node);
            }
            info.uselessReturns = [];
        }

        /**
         * Removes the return statements on the current segments from the useless
         * return statement list.
         *
         * This function will be called at every statement except FunctionDeclaration,
         * BlockStatement, and BreakStatement.
         *
         * - FunctionDeclarations are always executed whether it's returned or not.
         * - BlockStatements do nothing.
         * - BreakStatements go the next merely.
         * @returns {void}
         */
        function markReturnStatementsOnCurrentSegmentsAsUsed() {
            scopeInfo
                .codePath
                .currentSegments
                .forEach(markReturnStatementsOnSegmentAsUsed);
        }

        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------

        return {

            // Makes and pushes a new scope information.
            onCodePathStart(codePath) {

Review comment (suggestion):
I think we should check all try block statements in the list instead of just the first one. Otherwise, this would still be a false negative:

```js
function foo() {
    try {
        bar();
    } catch {
        try {
            baz();
            return; // false negative
        } catch {
            qux();
        }
    }
}

```

Code after:
                    .filter(prevSegment => !usedUnreachableSegments.has(prevSegment))
                    .forEach(prevSegment => markReturnStatementsOnSegmentAsUsed(prevSegment, usedUnreachableSegments));
                return;
            }

            const info = segmentInfoMap.get(segment);

            info.uselessReturns = info.uselessReturns.filter(node => {
                if (scopeInfo.traversedTryBlockStatements && scopeInfo.traversedTryBlockStatements.length > 0) {
                    const returnInitialRange = node.range[0];
                    const returnFinalRange = node.range[1];

                    const areBlocksInRange = scopeInfo.traversedTryBlockStatements.some(tryBlockStatement => {
                        const blockInitialRange = tryBlockStatement.range[0];
                        const blockFinalRange = tryBlockStatement.range[1];

                        return (
                            returnInitialRange >= blockInitialRange &&
                            returnFinalRange <= blockFinalRange
                        );
                    });

                    if (areBlocksInRange) {
                        return true;
                    }
                }

                remove(scopeInfo.uselessReturns, node);
                return false;
            });
        }

        /**
         * Removes the return statements on the current segments from the useless
         * return statement list.
         *
         * This function will be called at every statement except FunctionDeclaration,
         * BlockStatement, and BreakStatement.
         *
         * - FunctionDeclarations are always executed whether it's returned or not.
         * - BlockStatements do nothing.
         * - BreakStatements go the next merely.
         * @returns {void}
         */
        function markReturnStatementsOnCurrentSegmentsAsUsed() {
            scopeInfo
                .codePath
                .currentSegments
                .forEach(segment => markReturnStatementsOnSegmentAsUsed(segment, new Set()));
        }