1 | /**
|
2 | * @fileoverview Checks for unreachable code due to return, throws, break, and continue.
|
3 | * @author Joel Feenstra
|
4 | */
|
5 | ;
|
6 |
|
7 | //------------------------------------------------------------------------------
|
8 | // Helpers
|
9 | //------------------------------------------------------------------------------
|
10 |
|
11 |
|
12 | function report(context, node, unreachableType) {
|
13 | context.report(node, "Found unexpected statement after a {{type}}.", { type: unreachableType });
|
14 | }
|
15 |
|
16 |
|
17 | //------------------------------------------------------------------------------
|
18 | // Rule Definition
|
19 | //------------------------------------------------------------------------------
|
20 |
|
21 | module.exports = function(context) {
|
22 |
|
23 | function checkForUnreachable(node) {
|
24 | switch (node.type) {
|
25 | case "ReturnStatement":
|
26 | return "return";
|
27 | case "ThrowStatement":
|
28 | return "throw";
|
29 | case "ContinueStatement":
|
30 | return "continue";
|
31 | case "BreakStatement":
|
32 | return "break";
|
33 | default:
|
34 | return false;
|
35 | }
|
36 | }
|
37 |
|
38 | /**
|
39 | * Checks if a node is an exception for no-unreachable because of variable/function hoisting
|
40 | * @param {ASTNode} node The AST node to check.
|
41 | * @returns {boolean} if the node doesn't trigger unreachable
|
42 | * @private
|
43 | */
|
44 | function isUnreachableAllowed(node) {
|
45 | return node.type === "FunctionDeclaration" ||
|
46 | node.type === "VariableDeclaration" &&
|
47 | node.declarations.every(function(declaration){
|
48 | return declaration.type === "VariableDeclarator" && declaration.init === null;
|
49 | });
|
50 | }
|
51 |
|
52 | /**
|
53 | * Loops through a field of a node and checks if its children fulfill conditions to trigger the unreachable report.
|
54 | * @param {ASTNode} node The AST node to check.
|
55 | * @param {string} field The field that represents the children of the node.
|
56 | * @returns {void}
|
57 | * @private
|
58 | */
|
59 | function checkNodeFieldForUnreachable(node, field) {
|
60 | var i, unreachableType = false;
|
61 | for (i = 1; i < node[field].length; i++) {
|
62 | unreachableType = unreachableType || checkForUnreachable(node[field][i - 1]);
|
63 | if (unreachableType && !isUnreachableAllowed(node[field][i])) {
|
64 | report(context, node[field][i], unreachableType);
|
65 | }
|
66 | }
|
67 | }
|
68 |
|
69 | return {
|
70 | "BlockStatement": function(node) {
|
71 | checkNodeFieldForUnreachable(node, "body");
|
72 | },
|
73 |
|
74 | "SwitchCase": function(node) {
|
75 | checkNodeFieldForUnreachable(node, "consequent");
|
76 | }
|
77 | };
|
78 |
|
79 | };
|