1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
/**
* @fileoverview Checks for unreachable code due to return, throws, break, and continue.
* @author Joel Feenstra
*/
"use strict";
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
function report(context, node, unreachableType) {
var keyword;
switch (unreachableType) {
case "BreakStatement":
keyword = "break";
break;
case "ContinueStatement":
keyword = "continue";
break;
case "ReturnStatement":
keyword = "return";
break;
case "ThrowStatement":
keyword = "throw";
break;
default:
return;
}
context.report(node, "Found unexpected statement after a {{type}}.", { type: keyword });
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = function(context) {
/**
* Checks if a node is an exception for no-unreachable because of variable/function hoisting
* @param {ASTNode} node The AST node to check.
* @returns {boolean} if the node doesn't trigger unreachable
* @private
*/
function isUnreachableAllowed(node) {
return node.type === "FunctionDeclaration" ||
node.type === "VariableDeclaration" &&
node.declarations.every(function(declaration) {
return declaration.type === "VariableDeclarator" && declaration.init === null;
});
}
/*
* Verifies that the given node is the last node or followed exclusively by
* hoisted declarations
* @param {ASTNode} node Node that should be the last node
* @returns {void}
* @private
*/
function checkNode(node) {
var parent = context.getAncestors().pop();
var field, i, sibling;
switch (parent.type) {
case "SwitchCase":
field = "consequent";
break;
case "Program":
case "BlockStatement":
field = "body";
break;
default:
return;
}
for (i = parent[field].length - 1; i >= 0; i--) {
sibling = parent[field][i];
if (sibling === node) {
return; // Found the last reachable statement, all done
}
if (!isUnreachableAllowed(sibling)) {
report(context, sibling, node.type);
}
}
}
return {
"ReturnStatement": checkNode,
"ThrowStatement": checkNode,
"ContinueStatement": checkNode,
"BreakStatement": checkNode
};
};
|