eslint-plugin-sonarjs
Version:
SonarJS rules for ESLint
112 lines • 4.77 kB
JavaScript
;
/*
* eslint-plugin-sonarjs
* Copyright (C) 2018 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// https://jira.sonarsource.com/browse/RSPEC-3699
const nodes_1 = require("../utils/nodes");
function isReturnValueUsed(callExpr, context) {
const parent = nodes_1.getParent(context);
if (!parent) {
return false;
}
if (parent.type === "LogicalExpression") {
return parent.left === callExpr;
}
if (parent.type === "SequenceExpression") {
return parent.expressions[parent.expressions.length - 1] === callExpr;
}
if (parent.type === "ConditionalExpression") {
return parent.test === callExpr;
}
return (parent.type !== "ExpressionStatement" &&
parent.type !== "ArrowFunctionExpression" &&
parent.type !== "UnaryExpression" &&
parent.type !== "AwaitExpression" &&
parent.type !== "ReturnStatement" &&
parent.type !== "ThrowStatement");
}
const rule = {
meta: {
type: "problem",
},
create(context) {
const callExpressionsToCheck = new Map();
const functionsWithReturnValue = new Set();
return {
CallExpression(node) {
const callExpr = node;
if (!isReturnValueUsed(callExpr, context)) {
return;
}
const scope = context.getScope();
const reference = scope.references.find(ref => ref.identifier === callExpr.callee);
if (reference && reference.resolved) {
const variable = reference.resolved;
if (variable.defs.length === 1) {
const definition = variable.defs[0];
if (definition.type === "FunctionName") {
callExpressionsToCheck.set(reference.identifier, definition.node);
}
else if (definition.type === "Variable") {
const { init } = definition.node;
if (init && (nodes_1.isFunctionExpression(init) || nodes_1.isArrowFunctionExpression(init))) {
callExpressionsToCheck.set(reference.identifier, init);
}
}
}
}
},
ReturnStatement(node) {
const returnStmt = node;
if (returnStmt.argument) {
const ancestors = [...context.getAncestors()].reverse();
const functionNode = ancestors.find(node => node.type === "FunctionExpression" ||
node.type === "FunctionDeclaration" ||
node.type === "ArrowFunctionExpression");
functionsWithReturnValue.add(functionNode);
}
},
ArrowFunctionExpression(node) {
const arrowFunc = node;
if (arrowFunc.expression) {
functionsWithReturnValue.add(arrowFunc);
}
},
":function"(node) {
const func = node;
if (func.async || func.generator || (nodes_1.isBlockStatement(func.body) && func.body.body.length === 0)) {
functionsWithReturnValue.add(func);
}
},
"Program:exit"() {
callExpressionsToCheck.forEach((functionDeclaration, callee) => {
if (!functionsWithReturnValue.has(functionDeclaration)) {
context.report({
message: `Remove this use of the output from "{{name}}"; "{{name}}" doesn't return anything.`,
node: callee,
data: { name: callee.name },
});
}
});
},
};
},
};
module.exports = rule;
//# sourceMappingURL=no-use-of-empty-return-value.js.map