Skip to content

Commit cc3bd00

Browse files
Tanujkanti4441snitin315
andauthoredMar 18, 2025··
fix: reporting variable used in catch block in no-useless-assignment (#19423)
* fix: reporting variable in catch block * revert change in best-practice.d.ts file * check variable in stored catch block * check variable inside catch in varify function * update JSDoc comments * apply fix for read references * revert changes in best-practice.dts * apply suggestion * remove space * use target scopeStack * ignore assignments in try blocks * add know limitations section in docs * only ignore assignment inside try block * remove space * Update docs/src/rules/no-useless-assignment.md Co-authored-by: Nitin Kumar <snitin315@gmail.com> --------- Co-authored-by: Nitin Kumar <snitin315@gmail.com>
1 parent cd83eaa commit cc3bd00

File tree

3 files changed

+94
-1
lines changed

3 files changed

+94
-1
lines changed
 

‎docs/src/rules/no-useless-assignment.md

+35
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,41 @@ function fn() {
151151

152152
:::
153153

154+
## Known Limitations
155+
156+
This rule does not report certain variable reassignments when they occur inside the `try` block. This is intentional because such assignments may still be observed within the corresponding `catch` block or after the `try-catch` structure, due to potential early exits or error handling logic.
157+
158+
```js
159+
function foo() {
160+
let bar;
161+
try {
162+
bar = 2;
163+
unsafeFn();
164+
return { error: undefined };
165+
} catch {
166+
return { bar }; // `bar` is observed in the catch block
167+
}
168+
}
169+
function unsafeFn() {
170+
throw new Error();
171+
}
172+
173+
function foo() {
174+
let bar;
175+
try {
176+
bar = 2; // This assignment is relevant if unsafeFn() throws an error
177+
unsafeFn();
178+
bar = 4;
179+
} catch {
180+
// Error handling
181+
}
182+
return bar;
183+
}
184+
function unsafeFn() {
185+
throw new Error();
186+
}
187+
```
188+
154189
## When Not To Use It
155190

156191
If you don't want to be notified about values that are never read, you can safely disable this rule.

‎lib/rules/no-useless-assignment.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ module.exports = {
151151
* @property {Record<string, ScopeStackSegmentInfo>} segments The map of ScopeStackSegmentInfo.
152152
* @property {Set<CodePathSegment>} currentSegments The current CodePathSegments.
153153
* @property {Map<Variable, AssignmentInfo[]>} assignments The map of list of AssignmentInfo for each variable.
154+
* @property {Array} tryStatementBlocks The array of TryStatement block nodes in this scope stack.
154155
*/
155156
/**
156157
* @typedef {Object} ScopeStackSegmentInfo
@@ -229,6 +230,16 @@ module.exports = {
229230
*/
230231
function verifyAssignmentIsUsed(targetAssignment, allAssignments) {
231232

233+
// Skip assignment if it is in a try block.
234+
const isAssignmentInTryBlock = target.tryStatementBlocks.some(tryBlock =>
235+
tryBlock.range[0] <= targetAssignment.identifier.range[0] &&
236+
targetAssignment.identifier.range[1] <= tryBlock.range[1]
237+
);
238+
239+
if (isAssignmentInTryBlock) {
240+
return;
241+
}
242+
232243
/**
233244
* @typedef {Object} SubsequentSegmentData
234245
* @property {CodePathSegment} segment The code path segment
@@ -445,7 +456,8 @@ module.exports = {
445456
scope,
446457
segments: Object.create(null),
447458
currentSegments: new Set(),
448-
assignments: new Map()
459+
assignments: new Map(),
460+
tryStatementBlocks: []
449461
};
450462
codePathStartScopes.add(scopeStack.scope);
451463
},
@@ -463,6 +475,9 @@ module.exports = {
463475
onCodePathSegmentEnd(segment) {
464476
scopeStack.currentSegments.delete(segment);
465477
},
478+
TryStatement(node) {
479+
scopeStack.tryStatementBlocks.push(node.block);
480+
},
466481
Identifier(node) {
467482
for (const segment of scopeStack.currentSegments) {
468483
const segmentInfo = scopeStack.segments[segment.id];

‎tests/lib/rules/no-useless-assignment.js

+43
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,49 @@ ruleTester.run("no-useless-assignment", rule, {
370370
console.log(a, b);`,
371371
`let { a, b: {c = a} = {} } = obj;
372372
console.log(c);`,
373+
374+
// ignore assignments in try block
375+
`function foo(){
376+
let bar;
377+
try {
378+
bar = 2;
379+
unsafeFn();
380+
return { error: undefined };
381+
} catch {
382+
return { bar };
383+
}
384+
}
385+
function unsafeFn() {
386+
throw new Error();
387+
}`,
388+
`function foo(){
389+
let bar, baz;
390+
try {
391+
bar = 2;
392+
unsafeFn();
393+
return { error: undefined };
394+
} catch {
395+
baz = bar;
396+
}
397+
return baz;
398+
}
399+
function unsafeFn() {
400+
throw new Error();
401+
}`,
402+
`function foo(){
403+
let bar;
404+
try {
405+
bar = 2;
406+
unsafeFn();
407+
bar = 4;
408+
} catch {
409+
// handle error
410+
}
411+
return bar;
412+
}
413+
function unsafeFn() {
414+
throw new Error();
415+
}`,
373416
{
374417
code: `/*eslint test/jsx:1*/
375418
function App() {

0 commit comments

Comments
 (0)
Please sign in to comment.