From 52ebbfaab678a0453adcf0570141dde7c38840ad Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 29 Oct 2023 19:35:26 +0900 Subject: [PATCH 1/2] fix(eslint-plugin): [no-unused-vars] handle logical assignment --- .../src/util/collectUnusedVariables.ts | 12 ++++++++ .../no-unused-vars/no-unused-vars.test.ts | 30 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/packages/eslint-plugin/src/util/collectUnusedVariables.ts b/packages/eslint-plugin/src/util/collectUnusedVariables.ts index 8ec63de10dc6..fb013abbedf2 100644 --- a/packages/eslint-plugin/src/util/collectUnusedVariables.ts +++ b/packages/eslint-plugin/src/util/collectUnusedVariables.ts @@ -439,6 +439,17 @@ function isExported(variable: TSESLint.Scope.Variable): boolean { }); } +const LOGICAL_ASSIGNMENT_OPERATORS = new Set(['&&=', '||=', '??=']); + +/** + * Checks whether the given operator is a logical assignment operator or not. + * @param operator The operator + * @returns True if the operator is a logical assignment operator. + */ +function isLogicalAssignmentOperator(operator: string): boolean { + return LOGICAL_ASSIGNMENT_OPERATORS.has(operator); +} + /** * Determines if the variable is used. * @param variable The variable to check. @@ -701,6 +712,7 @@ function isUsedVariable(variable: TSESLint.Scope.Variable): boolean { ref.isRead() && // in RHS of an assignment for itself. e.g. `a = a + 1` // self update. e.g. `a += 1`, `a++` ((parent.type === AST_NODE_TYPES.AssignmentExpression && + !isLogicalAssignmentOperator(parent.operator) && grandparent.type === AST_NODE_TYPES.ExpressionStatement && parent.left === id) || (parent.type === AST_NODE_TYPES.UpdateExpression && diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts index 636e2fe8d2c1..baed3954060c 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts @@ -1099,6 +1099,18 @@ interface Foo { bar: string; } `, + ` +let foo = 1; +foo ??= 2; + `, + ` +let foo = 1; +foo &&= 2; + `, + ` +let foo = 1; +foo ||= 2; + `, ], invalid: [ @@ -1844,5 +1856,23 @@ const Foo = 'bar'; }, ], }, + { + code: ` +let foo = 1; +foo += 1; + `, + errors: [ + { + messageId: 'unusedVar', + line: 3, + column: 1, + data: { + varName: 'foo', + action: 'assigned a value', + additional: '', + }, + }, + ], + }, ], }); From fcb510a88b510f715997e7c8a84540ac099935f5 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Mon, 30 Oct 2023 21:57:22 +0900 Subject: [PATCH 2/2] refactor --- .../eslint-plugin/src/util/collectUnusedVariables.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/eslint-plugin/src/util/collectUnusedVariables.ts b/packages/eslint-plugin/src/util/collectUnusedVariables.ts index fb013abbedf2..518a696911b7 100644 --- a/packages/eslint-plugin/src/util/collectUnusedVariables.ts +++ b/packages/eslint-plugin/src/util/collectUnusedVariables.ts @@ -441,15 +441,6 @@ function isExported(variable: TSESLint.Scope.Variable): boolean { const LOGICAL_ASSIGNMENT_OPERATORS = new Set(['&&=', '||=', '??=']); -/** - * Checks whether the given operator is a logical assignment operator or not. - * @param operator The operator - * @returns True if the operator is a logical assignment operator. - */ -function isLogicalAssignmentOperator(operator: string): boolean { - return LOGICAL_ASSIGNMENT_OPERATORS.has(operator); -} - /** * Determines if the variable is used. * @param variable The variable to check. @@ -712,7 +703,7 @@ function isUsedVariable(variable: TSESLint.Scope.Variable): boolean { ref.isRead() && // in RHS of an assignment for itself. e.g. `a = a + 1` // self update. e.g. `a += 1`, `a++` ((parent.type === AST_NODE_TYPES.AssignmentExpression && - !isLogicalAssignmentOperator(parent.operator) && + !LOGICAL_ASSIGNMENT_OPERATORS.has(parent.operator) && grandparent.type === AST_NODE_TYPES.ExpressionStatement && parent.left === id) || (parent.type === AST_NODE_TYPES.UpdateExpression &&