Skip to content

Commit

Permalink
Fix FP 3699 (no-use-of-empty-return-values) to handle ambient functio…
Browse files Browse the repository at this point in the history
…ns (#451)
  • Loading branch information
zglicz committed Mar 8, 2024
1 parent 252b02a commit 710b5f1
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 14 deletions.
2 changes: 1 addition & 1 deletion scripts/test-ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set -euo pipefail
# variable is set in dockerfile
if [ "${SONARCLOUD_ANALYSIS:-}" == "true" ]; then
echo 'Running tests with coverage and reporter'
npm run test -- --coverage --testResultsProcessor jest-sonar-reporter
npm run test -- --maxWorkers=50% --coverage --testResultsProcessor jest-sonar-reporter
else
echo 'Running tests'
npm run test
Expand Down
42 changes: 29 additions & 13 deletions src/rules/no-use-of-empty-return-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,41 @@
*/
// https://sonarsource.github.io/rspec/#/rspec/S3699

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

const EMPTY_RETURN_VALUE_KEYWORDS = new Set<TSESTree.AST_NODE_TYPES>([
TSESTree.AST_NODE_TYPES.TSVoidKeyword,
TSESTree.AST_NODE_TYPES.TSNeverKeyword,
TSESTree.AST_NODE_TYPES.TSUndefinedKeyword,
]);

function isReturnValueUsed(callExpr: TSESTree.Node) {
const { parent } = callExpr;
if (!parent) {
return false;
}

if (parent.type === 'LogicalExpression') {
if (parent.type === TSESTree.AST_NODE_TYPES.LogicalExpression) {
return parent.left === callExpr;
}

if (parent.type === 'SequenceExpression') {
if (parent.type === TSESTree.AST_NODE_TYPES.SequenceExpression) {
return parent.expressions[parent.expressions.length - 1] === callExpr;
}

if (parent.type === 'ConditionalExpression') {
if (parent.type === TSESTree.AST_NODE_TYPES.ConditionalExpression) {
return parent.test === callExpr;
}

return (
parent.type !== 'ExpressionStatement' &&
parent.type !== 'ArrowFunctionExpression' &&
parent.type !== 'UnaryExpression' &&
parent.type !== 'AwaitExpression' &&
parent.type !== 'ReturnStatement' &&
parent.type !== 'ThrowStatement'
parent.type !== TSESTree.AST_NODE_TYPES.ExpressionStatement &&
parent.type !== TSESTree.AST_NODE_TYPES.ArrowFunctionExpression &&
parent.type !== TSESTree.AST_NODE_TYPES.UnaryExpression &&
parent.type !== TSESTree.AST_NODE_TYPES.AwaitExpression &&
parent.type !== TSESTree.AST_NODE_TYPES.ReturnStatement &&
parent.type !== TSESTree.AST_NODE_TYPES.ThrowStatement
);
}

Expand Down Expand Up @@ -102,9 +108,9 @@ const rule: TSESLint.RuleModule<string, string[]> = {
const ancestors = [...context.getAncestors()].reverse();
const functionNode = ancestors.find(
node =>
node.type === 'FunctionExpression' ||
node.type === 'FunctionDeclaration' ||
node.type === 'ArrowFunctionExpression',
node.type === TSESTree.AST_NODE_TYPES.FunctionExpression ||
node.type === TSESTree.AST_NODE_TYPES.FunctionDeclaration ||
node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression,
);

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

TSDeclareFunction(node: TSESTree.Node) {
const declareFunction = node as TSESTree.TSDeclareFunction;
if (
declareFunction.returnType?.typeAnnotation.type &&
!EMPTY_RETURN_VALUE_KEYWORDS.has(declareFunction.returnType?.typeAnnotation.type)
) {
functionsWithReturnValue.add(declareFunction);
}
},

'Program:exit'() {
callExpressionsToCheck.forEach((functionDeclaration, callee) => {
if (!functionsWithReturnValue.has(functionDeclaration)) {
Expand Down
4 changes: 4 additions & 0 deletions tests/rules/no-use-of-empty-return-value.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ ruleTester.run('no-use-of-empty-return-value', rule, {
},
{ code: 'function* noReturn() { yield 1; } noReturn().next();' },
{ code: 'function* noReturn() { yield 1; } noReturn();' },
{ code: 'declare function withReturn(): number; let x = withReturn();' },
],
invalid: [
invalidPrefixWithFunction('console.log(noReturn());'),
Expand All @@ -69,6 +70,9 @@ ruleTester.run('no-use-of-empty-return-value', rule, {
),
invalid('var funcExpr = function noReturn () { 1; console.log(noReturn()); };'),
invalid('var noReturn = () => { var x = () => {return 1} }; x = noReturn();'),
invalid('declare function noReturn(): never; let x = noReturn();'),
invalid('declare function noReturn(): void; let x = noReturn();'),
invalid('declare function noReturn(): undefined; let x = noReturn();'),
],
});

Expand Down

0 comments on commit 710b5f1

Please sign in to comment.