2 * @fileoverview Checks for unreachable code due to return, throws, break, and continue.
3 * @author Joel Feenstra
7 //------------------------------------------------------------------------------
9 //------------------------------------------------------------------------------
12 * Checks whether or not a given variable declarator has the initializer.
13 * @param {ASTNode} node A VariableDeclarator node to check.
14 * @returns {boolean} `true` if the node has the initializer.
16 function isInitialized(node) {
17 return Boolean(node.init);
21 * Checks whether or not a given code path segment is unreachable.
22 * @param {CodePathSegment} segment A CodePathSegment to check.
23 * @returns {boolean} `true` if the segment is unreachable.
25 function isUnreachable(segment) {
26 return !segment.reachable;
30 * The class to distinguish consecutive unreachable statements.
32 class ConsecutiveRange {
33 constructor(sourceCode) {
34 this.sourceCode = sourceCode;
35 this.startNode = null;
40 * The location object of this range.
45 start: this.startNode.loc.start,
46 end: this.endNode.loc.end
51 * `true` if this range is empty.
55 return !(this.startNode && this.endNode);
59 * Checks whether the given node is inside of this range.
60 * @param {ASTNode|Token} node The node to check.
61 * @returns {boolean} `true` if the node is inside of this range.
65 node.range[0] >= this.startNode.range[0] &&
66 node.range[1] <= this.endNode.range[1]
71 * Checks whether the given node is consecutive to this range.
72 * @param {ASTNode} node The node to check.
73 * @returns {boolean} `true` if the node is consecutive to this range.
76 return this.contains(this.sourceCode.getTokenBefore(node));
80 * Merges the given node to this range.
81 * @param {ASTNode} node The node to merge.
89 * Resets this range by the given node or null.
90 * @param {ASTNode|null} node The node to reset, or null.
94 this.startNode = this.endNode = node;
98 //------------------------------------------------------------------------------
100 //------------------------------------------------------------------------------
107 description: "disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
108 category: "Possible Errors",
110 url: "https://eslint.org/docs/rules/no-unreachable"
117 let currentCodePath = null;
119 const range = new ConsecutiveRange(context.getSourceCode());
122 * Reports a given node if it's unreachable.
123 * @param {ASTNode} node A statement node to report.
126 function reportIfUnreachable(node) {
129 if (node && currentCodePath.currentSegments.every(isUnreachable)) {
131 // Store this statement to distinguish consecutive statements.
137 // Skip if this statement is inside of the current range.
138 if (range.contains(node)) {
142 // Merge if this statement is consecutive to the current range.
143 if (range.isConsecutive(node)) {
152 * Report the current range since this statement is reachable or is
153 * not consecutive to the current range.
155 if (!range.isEmpty) {
157 message: "Unreachable code.",
159 node: range.startNode
163 // Update the current range.
164 range.reset(nextNode);
169 // Manages the current code path.
170 onCodePathStart(codePath) {
171 currentCodePath = codePath;
175 currentCodePath = currentCodePath.upper;
178 // Registers for all statement nodes (excludes FunctionDeclaration).
179 BlockStatement: reportIfUnreachable,
180 BreakStatement: reportIfUnreachable,
181 ClassDeclaration: reportIfUnreachable,
182 ContinueStatement: reportIfUnreachable,
183 DebuggerStatement: reportIfUnreachable,
184 DoWhileStatement: reportIfUnreachable,
185 ExpressionStatement: reportIfUnreachable,
186 ForInStatement: reportIfUnreachable,
187 ForOfStatement: reportIfUnreachable,
188 ForStatement: reportIfUnreachable,
189 IfStatement: reportIfUnreachable,
190 ImportDeclaration: reportIfUnreachable,
191 LabeledStatement: reportIfUnreachable,
192 ReturnStatement: reportIfUnreachable,
193 SwitchStatement: reportIfUnreachable,
194 ThrowStatement: reportIfUnreachable,
195 TryStatement: reportIfUnreachable,
197 VariableDeclaration(node) {
198 if (node.kind !== "var" || node.declarations.some(isInitialized)) {
199 reportIfUnreachable(node);
203 WhileStatement: reportIfUnreachable,
204 WithStatement: reportIfUnreachable,
205 ExportNamedDeclaration: reportIfUnreachable,
206 ExportDefaultDeclaration: reportIfUnreachable,
207 ExportAllDeclaration: reportIfUnreachable,
210 reportIfUnreachable();