eslint: Bug: Incorrect code path analysis for `return` in try blocks with catch clause
Environment
Node version: v20.6.1 npm version: v9.8.1 Local ESLint version: Not found Global ESLint version: v8.49.0 Operating System: darwin 22.5.0
What parser are you using?
Default (Espree)
What did you do?
// test.js
function foo() {
try {
bar();
return;
} catch {}
baz();
}
What did you expect to happen?
From https://github.com/eslint/eslint/pull/16593#discussion_r1042004643:
code path analysis considers segments containing
return
s from the try block as possible previous segments for segments in the catch block. This is logically incorrect, as the execution afterreturn;
cannot go into the catch block, but fixing this in the code path analysis would be a breaking change.
I can reproduce this in current versions of ESLint for the above code. For example, when I run this command in a zsh terminal:
ESLINT_USE_FLAT_CONFIG=true DEBUG=eslint:code-path npx eslint --no-config-lookup test.js
I’m getting this Graphviz code in the output:
digraph {
node[shape=box,style="rounded,filled",fillcolor=white];
initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
s2_1[label="FunctionDeclaration:enter\nIdentifier (foo)\nBlockStatement:enter\nTryStatement:enter\nBlockStatement:enter\nExpressionStatement:enter\nCallExpression:enter\nIdentifier (bar)"];
s2_2[label="CallExpression:exit\nExpressionStatement:exit\nReturnStatement"];
s2_3[style="rounded,dashed,filled",fillcolor="#FF9800",label="<<unreachable>>\nBlockStatement:exit"];
s2_4[label="CatchClause:enter\nBlockStatement\nCatchClause:exit"];
s2_5[label="TryStatement:exit\nExpressionStatement:enter\nCallExpression:enter\nIdentifier (baz)\nCallExpression:exit\nExpressionStatement:exit\nBlockStatement:exit\nFunctionDeclaration:exit"];
initial->s2_1->s2_2->s2_3->s2_4->s2_5;
s2_1->s2_4;
s2_3->s2_5;
s2_2->final;
s2_5->final;
}
Notice the edge s2_3->s2_4
connecting the unreachable segment to the catch clause which seems wrong.
What actually happened?
There should be no parent-child connection from the unreachable segment after the return statement to the segment with the catch clause.
stateDiagram-v2
classDef common fill: white, stroke: black
class s2_1, s2_2, s2_4, s2_3, s2_5 common
classDef unreachable fill: #FF9800, stroke-dasharray: 5 5
class s2_3 unreachable
state "FunctionDeclaration:enter\nIdentifier (foo)\nBlockStatement:enter\nTryStatement:enter\nBlockStatement:enter\nExpressionStatement:enter\nCallExpression:enter\nIdentifier (bar)" as s2_1
state "CallExpression:exit\nExpressionStatement:exit\nReturnStatement" as s2_2
state "CatchClause:enter\nBlockStatement\nCatchClause:exit" as s2_4
state "❮❮unreachable❯❯\nBlockStatement:exit" as s2_3
state "TryStatement:exit\nExpressionStatement:enter\nCallExpression:enter\nIdentifier (baz)\nCallExpression:exit\nExpressionStatement:exit\nBlockStatement:exit\nFunctionDeclaration:exit" as s2_5
[*] --> s2_1
s2_1 --> s2_2
s2_1 --> s2_4
s2_2 --> s2_3
s2_4 --> s2_5
s2_3 --> s2_4: WRONG!
s2_3 --> s2_5
s2_2 --> [*]
s2_5 --> [*]
Link to Minimal Reproducible Example
https://stackblitz.com/edit/stackblitz-starters-3zwhfs
Participation
- I am willing to submit a pull request for this issue.
Additional comments
I haven’t figured out how to fix this yet, so I can’t say if the fix would have any side effects.
This bug can be worked around (we are doing this for example in the no-useless-return
rule), so it’s an open question whether this should be tackled in v9.
About this issue
- Original URL
- State: open
- Created 9 months ago
- Comments: 30 (30 by maintainers)
Commits related to this issue
- fix!: Ensure catch block after return in try is correct. Fixes #17579 — committed to eslint/eslint by nzakas 9 months ago
That should be the beta.1 release.
Okay, no problem. This is one of the last two issues we had planned for the beta, so if you don’t think you’ll be able to address this soonish, we can move it to v10.
Thanks @fasttime. I’d love to get this done, but also realize that code path analysis is hard and I don’t think it should block v9.
I think this is something we should fix. Whether or not it’s practical to do in the v9 timeframe is the question.
I’ve just spent a bunch of time digging into code path analysis so I’ll take a look.