.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-unreachable.js
1 /**
2  * @fileoverview Checks for unreachable code due to return, throws, break, and continue.
3  * @author Joel Feenstra
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Helpers
9 //------------------------------------------------------------------------------
10
11 /**
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.
15  */
16 function isInitialized(node) {
17     return Boolean(node.init);
18 }
19
20 /**
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.
24  */
25 function isUnreachable(segment) {
26     return !segment.reachable;
27 }
28
29 /**
30  * The class to distinguish consecutive unreachable statements.
31  */
32 class ConsecutiveRange {
33     constructor(sourceCode) {
34         this.sourceCode = sourceCode;
35         this.startNode = null;
36         this.endNode = null;
37     }
38
39     /**
40      * The location object of this range.
41      * @type {Object}
42      */
43     get location() {
44         return {
45             start: this.startNode.loc.start,
46             end: this.endNode.loc.end
47         };
48     }
49
50     /**
51      * `true` if this range is empty.
52      * @type {boolean}
53      */
54     get isEmpty() {
55         return !(this.startNode && this.endNode);
56     }
57
58     /**
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.
62      */
63     contains(node) {
64         return (
65             node.range[0] >= this.startNode.range[0] &&
66             node.range[1] <= this.endNode.range[1]
67         );
68     }
69
70     /**
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.
74      */
75     isConsecutive(node) {
76         return this.contains(this.sourceCode.getTokenBefore(node));
77     }
78
79     /**
80      * Merges the given node to this range.
81      * @param {ASTNode} node The node to merge.
82      * @returns {void}
83      */
84     merge(node) {
85         this.endNode = node;
86     }
87
88     /**
89      * Resets this range by the given node or null.
90      * @param {ASTNode|null} node The node to reset, or null.
91      * @returns {void}
92      */
93     reset(node) {
94         this.startNode = this.endNode = node;
95     }
96 }
97
98 //------------------------------------------------------------------------------
99 // Rule Definition
100 //------------------------------------------------------------------------------
101
102 module.exports = {
103     meta: {
104         type: "problem",
105
106         docs: {
107             description: "disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
108             category: "Possible Errors",
109             recommended: true,
110             url: "https://eslint.org/docs/rules/no-unreachable"
111         },
112
113         schema: [],
114
115         messages: {
116             unreachableCode: "Unreachable code."
117         }
118     },
119
120     create(context) {
121         let currentCodePath = null;
122
123         const range = new ConsecutiveRange(context.getSourceCode());
124
125         /**
126          * Reports a given node if it's unreachable.
127          * @param {ASTNode} node A statement node to report.
128          * @returns {void}
129          */
130         function reportIfUnreachable(node) {
131             let nextNode = null;
132
133             if (node && currentCodePath.currentSegments.every(isUnreachable)) {
134
135                 // Store this statement to distinguish consecutive statements.
136                 if (range.isEmpty) {
137                     range.reset(node);
138                     return;
139                 }
140
141                 // Skip if this statement is inside of the current range.
142                 if (range.contains(node)) {
143                     return;
144                 }
145
146                 // Merge if this statement is consecutive to the current range.
147                 if (range.isConsecutive(node)) {
148                     range.merge(node);
149                     return;
150                 }
151
152                 nextNode = node;
153             }
154
155             /*
156              * Report the current range since this statement is reachable or is
157              * not consecutive to the current range.
158              */
159             if (!range.isEmpty) {
160                 context.report({
161                     messageId: "unreachableCode",
162                     loc: range.location,
163                     node: range.startNode
164                 });
165             }
166
167             // Update the current range.
168             range.reset(nextNode);
169         }
170
171         return {
172
173             // Manages the current code path.
174             onCodePathStart(codePath) {
175                 currentCodePath = codePath;
176             },
177
178             onCodePathEnd() {
179                 currentCodePath = currentCodePath.upper;
180             },
181
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,
200
201             VariableDeclaration(node) {
202                 if (node.kind !== "var" || node.declarations.some(isInitialized)) {
203                     reportIfUnreachable(node);
204                 }
205             },
206
207             WhileStatement: reportIfUnreachable,
208             WithStatement: reportIfUnreachable,
209             ExportNamedDeclaration: reportIfUnreachable,
210             ExportDefaultDeclaration: reportIfUnreachable,
211             ExportAllDeclaration: reportIfUnreachable,
212
213             "Program:exit"() {
214                 reportIfUnreachable();
215             }
216         };
217     }
218 };