123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- "use strict";
- function isInitialized(node) {
- return Boolean(node.init);
- }
- function isUnreachable(segment) {
- return !segment.reachable;
- }
- class ConsecutiveRange {
- constructor(sourceCode) {
- this.sourceCode = sourceCode;
- this.startNode = null;
- this.endNode = null;
- }
-
- get location() {
- return {
- start: this.startNode.loc.start,
- end: this.endNode.loc.end
- };
- }
-
- get isEmpty() {
- return !(this.startNode && this.endNode);
- }
-
- contains(node) {
- return (
- node.range[0] >= this.startNode.range[0] &&
- node.range[1] <= this.endNode.range[1]
- );
- }
-
- isConsecutive(node) {
- return this.contains(this.sourceCode.getTokenBefore(node));
- }
-
- merge(node) {
- this.endNode = node;
- }
-
- reset(node) {
- this.startNode = this.endNode = node;
- }
- }
- module.exports = {
- meta: {
- type: "problem",
- docs: {
- description: "Disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
- recommended: true,
- url: "https://eslint.org/docs/rules/no-unreachable"
- },
- schema: [],
- messages: {
- unreachableCode: "Unreachable code."
- }
- },
- create(context) {
- let currentCodePath = null;
-
- let constructorInfo = null;
-
- const range = new ConsecutiveRange(context.getSourceCode());
-
- function reportIfUnreachable(node) {
- let nextNode = null;
- if (node && (node.type === "PropertyDefinition" || currentCodePath.currentSegments.every(isUnreachable))) {
-
- if (range.isEmpty) {
- range.reset(node);
- return;
- }
-
- if (range.contains(node)) {
- return;
- }
-
- if (range.isConsecutive(node)) {
- range.merge(node);
- return;
- }
- nextNode = node;
- }
-
- if (!range.isEmpty) {
- context.report({
- messageId: "unreachableCode",
- loc: range.location,
- node: range.startNode
- });
- }
-
- range.reset(nextNode);
- }
- return {
-
- onCodePathStart(codePath) {
- currentCodePath = codePath;
- },
- onCodePathEnd() {
- currentCodePath = currentCodePath.upper;
- },
-
- BlockStatement: reportIfUnreachable,
- BreakStatement: reportIfUnreachable,
- ClassDeclaration: reportIfUnreachable,
- ContinueStatement: reportIfUnreachable,
- DebuggerStatement: reportIfUnreachable,
- DoWhileStatement: reportIfUnreachable,
- ExpressionStatement: reportIfUnreachable,
- ForInStatement: reportIfUnreachable,
- ForOfStatement: reportIfUnreachable,
- ForStatement: reportIfUnreachable,
- IfStatement: reportIfUnreachable,
- ImportDeclaration: reportIfUnreachable,
- LabeledStatement: reportIfUnreachable,
- ReturnStatement: reportIfUnreachable,
- SwitchStatement: reportIfUnreachable,
- ThrowStatement: reportIfUnreachable,
- TryStatement: reportIfUnreachable,
- VariableDeclaration(node) {
- if (node.kind !== "var" || node.declarations.some(isInitialized)) {
- reportIfUnreachable(node);
- }
- },
- WhileStatement: reportIfUnreachable,
- WithStatement: reportIfUnreachable,
- ExportNamedDeclaration: reportIfUnreachable,
- ExportDefaultDeclaration: reportIfUnreachable,
- ExportAllDeclaration: reportIfUnreachable,
- "Program:exit"() {
- reportIfUnreachable();
- },
-
- "MethodDefinition[kind='constructor']"() {
- constructorInfo = {
- upper: constructorInfo,
- hasSuperCall: false
- };
- },
- "MethodDefinition[kind='constructor']:exit"(node) {
- const { hasSuperCall } = constructorInfo;
- constructorInfo = constructorInfo.upper;
-
- if (!node.value.body) {
- return;
- }
- const classDefinition = node.parent.parent;
- if (classDefinition.superClass && !hasSuperCall) {
- for (const element of classDefinition.body.body) {
- if (element.type === "PropertyDefinition" && !element.static) {
- reportIfUnreachable(element);
- }
- }
- }
- },
- "CallExpression > Super.callee"() {
- if (constructorInfo) {
- constructorInfo.hasSuperCall = true;
- }
- }
- };
- }
- };
|