Skip to content
This repository was archived by the owner on Oct 3, 2024. It is now read-only.

Commit 710b5f1

Browse files
authored
Fix FP 3699 (no-use-of-empty-return-values) to handle ambient functions (#451)
1 parent 252b02a commit 710b5f1

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

scripts/test-ci.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ set -euo pipefail
77
# variable is set in dockerfile
88
if [ "${SONARCLOUD_ANALYSIS:-}" == "true" ]; then
99
echo 'Running tests with coverage and reporter'
10-
npm run test -- --coverage --testResultsProcessor jest-sonar-reporter
10+
npm run test -- --maxWorkers=50% --coverage --testResultsProcessor jest-sonar-reporter
1111
else
1212
echo 'Running tests'
1313
npm run test

src/rules/no-use-of-empty-return-value.ts

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,41 @@
1919
*/
2020
// https://sonarsource.github.io/rspec/#/rspec/S3699
2121

22-
import type { TSESTree, TSESLint } from '@typescript-eslint/experimental-utils';
22+
import { TSESTree, TSESLint } from '@typescript-eslint/experimental-utils';
2323
import { isFunctionExpression, isArrowFunctionExpression, isBlockStatement } from '../utils/nodes';
2424
import docsUrl from '../utils/docs-url';
2525

26+
const EMPTY_RETURN_VALUE_KEYWORDS = new Set<TSESTree.AST_NODE_TYPES>([
27+
TSESTree.AST_NODE_TYPES.TSVoidKeyword,
28+
TSESTree.AST_NODE_TYPES.TSNeverKeyword,
29+
TSESTree.AST_NODE_TYPES.TSUndefinedKeyword,
30+
]);
31+
2632
function isReturnValueUsed(callExpr: TSESTree.Node) {
2733
const { parent } = callExpr;
2834
if (!parent) {
2935
return false;
3036
}
3137

32-
if (parent.type === 'LogicalExpression') {
38+
if (parent.type === TSESTree.AST_NODE_TYPES.LogicalExpression) {
3339
return parent.left === callExpr;
3440
}
3541

36-
if (parent.type === 'SequenceExpression') {
42+
if (parent.type === TSESTree.AST_NODE_TYPES.SequenceExpression) {
3743
return parent.expressions[parent.expressions.length - 1] === callExpr;
3844
}
3945

40-
if (parent.type === 'ConditionalExpression') {
46+
if (parent.type === TSESTree.AST_NODE_TYPES.ConditionalExpression) {
4147
return parent.test === callExpr;
4248
}
4349

4450
return (
45-
parent.type !== 'ExpressionStatement' &&
46-
parent.type !== 'ArrowFunctionExpression' &&
47-
parent.type !== 'UnaryExpression' &&
48-
parent.type !== 'AwaitExpression' &&
49-
parent.type !== 'ReturnStatement' &&
50-
parent.type !== 'ThrowStatement'
51+
parent.type !== TSESTree.AST_NODE_TYPES.ExpressionStatement &&
52+
parent.type !== TSESTree.AST_NODE_TYPES.ArrowFunctionExpression &&
53+
parent.type !== TSESTree.AST_NODE_TYPES.UnaryExpression &&
54+
parent.type !== TSESTree.AST_NODE_TYPES.AwaitExpression &&
55+
parent.type !== TSESTree.AST_NODE_TYPES.ReturnStatement &&
56+
parent.type !== TSESTree.AST_NODE_TYPES.ThrowStatement
5157
);
5258
}
5359

@@ -102,9 +108,9 @@ const rule: TSESLint.RuleModule<string, string[]> = {
102108
const ancestors = [...context.getAncestors()].reverse();
103109
const functionNode = ancestors.find(
104110
node =>
105-
node.type === 'FunctionExpression' ||
106-
node.type === 'FunctionDeclaration' ||
107-
node.type === 'ArrowFunctionExpression',
111+
node.type === TSESTree.AST_NODE_TYPES.FunctionExpression ||
112+
node.type === TSESTree.AST_NODE_TYPES.FunctionDeclaration ||
113+
node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression,
108114
);
109115

110116
functionsWithReturnValue.add(functionNode as TSESTree.FunctionLike);
@@ -132,6 +138,16 @@ const rule: TSESLint.RuleModule<string, string[]> = {
132138
}
133139
},
134140

141+
TSDeclareFunction(node: TSESTree.Node) {
142+
const declareFunction = node as TSESTree.TSDeclareFunction;
143+
if (
144+
declareFunction.returnType?.typeAnnotation.type &&
145+
!EMPTY_RETURN_VALUE_KEYWORDS.has(declareFunction.returnType?.typeAnnotation.type)
146+
) {
147+
functionsWithReturnValue.add(declareFunction);
148+
}
149+
},
150+
135151
'Program:exit'() {
136152
callExpressionsToCheck.forEach((functionDeclaration, callee) => {
137153
if (!functionsWithReturnValue.has(functionDeclaration)) {

tests/rules/no-use-of-empty-return-value.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ ruleTester.run('no-use-of-empty-return-value', rule, {
5151
},
5252
{ code: 'function* noReturn() { yield 1; } noReturn().next();' },
5353
{ code: 'function* noReturn() { yield 1; } noReturn();' },
54+
{ code: 'declare function withReturn(): number; let x = withReturn();' },
5455
],
5556
invalid: [
5657
invalidPrefixWithFunction('console.log(noReturn());'),
@@ -69,6 +70,9 @@ ruleTester.run('no-use-of-empty-return-value', rule, {
6970
),
7071
invalid('var funcExpr = function noReturn () { 1; console.log(noReturn()); };'),
7172
invalid('var noReturn = () => { var x = () => {return 1} }; x = noReturn();'),
73+
invalid('declare function noReturn(): never; let x = noReturn();'),
74+
invalid('declare function noReturn(): void; let x = noReturn();'),
75+
invalid('declare function noReturn(): undefined; let x = noReturn();'),
7276
],
7377
});
7478

0 commit comments

Comments
 (0)