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"
116 unreachableCode: "Unreachable code."
121 let currentCodePath = null;
123 const range = new ConsecutiveRange(context.getSourceCode());
126 * Reports a given node if it's unreachable.
127 * @param {ASTNode} node A statement node to report.
130 function reportIfUnreachable(node) {
133 if (node && currentCodePath.currentSegments.every(isUnreachable)) {
135 // Store this statement to distinguish consecutive statements.
141 // Skip if this statement is inside of the current range.
142 if (range.contains(node)) {
146 // Merge if this statement is consecutive to the current range.
147 if (range.isConsecutive(node)) {
156 * Report the current range since this statement is reachable or is
157 * not consecutive to the current range.
159 if (!range.isEmpty) {
161 messageId: "unreachableCode",
163 node: range.startNode
167 // Update the current range.
168 range.reset(nextNode);
173 // Manages the current code path.
174 onCodePathStart(codePath) {
175 currentCodePath = codePath;
179 currentCodePath = currentCodePath.upper;
182 // Registers for all statement nodes (excludes FunctionDeclaration).
183 BlockStatement: reportIfUnreachable,
184 BreakStatement: reportIfUnreachable,
185 ClassDeclaration: reportIfUnreachable,
186 ContinueStatement: reportIfUnreachable,
187 DebuggerStatement: reportIfUnreachable,
188 DoWhileStatement: reportIfUnreachable,
189 ExpressionStatement: reportIfUnreachable,
190 ForInStatement: reportIfUnreachable,
191 ForOfStatement: reportIfUnreachable,
192 ForStatement: reportIfUnreachable,
193 IfStatement: reportIfUnreachable,
194 ImportDeclaration: reportIfUnreachable,
195 LabeledStatement: reportIfUnreachable,
196 ReturnStatement: reportIfUnreachable,
197 SwitchStatement: reportIfUnreachable,
198 ThrowStatement: reportIfUnreachable,
199 TryStatement: reportIfUnreachable,
201 VariableDeclaration(node) {
202 if (node.kind !== "var" || node.declarations.some(isInitialized)) {
203 reportIfUnreachable(node);
207 WhileStatement: reportIfUnreachable,
208 WithStatement: reportIfUnreachable,
209 ExportNamedDeclaration: reportIfUnreachable,
210 ExportDefaultDeclaration: reportIfUnreachable,
211 ExportAllDeclaration: reportIfUnreachable,
214 reportIfUnreachable();