some deletions
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / linter / code-path-analysis / code-path-analyzer.js
diff --git a/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js b/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js
deleted file mode 100644 (file)
index 6822ae2..0000000
+++ /dev/null
@@ -1,683 +0,0 @@
-/**
- * @fileoverview A class of the code path analyzer.
- * @author Toru Nagashima
- */
-
-"use strict";
-
-//------------------------------------------------------------------------------
-// Requirements
-//------------------------------------------------------------------------------
-
-const assert = require("assert"),
-    { breakableTypePattern } = require("../../shared/ast-utils"),
-    CodePath = require("./code-path"),
-    CodePathSegment = require("./code-path-segment"),
-    IdGenerator = require("./id-generator"),
-    debug = require("./debug-helpers");
-
-//------------------------------------------------------------------------------
-// Helpers
-//------------------------------------------------------------------------------
-
-/**
- * Checks whether or not a given node is a `case` node (not `default` node).
- * @param {ASTNode} node A `SwitchCase` node to check.
- * @returns {boolean} `true` if the node is a `case` node (not `default` node).
- */
-function isCaseNode(node) {
-    return Boolean(node.test);
-}
-
-/**
- * Checks whether the given logical operator is taken into account for the code
- * path analysis.
- * @param {string} operator The operator found in the LogicalExpression node
- * @returns {boolean} `true` if the operator is "&&" or "||"
- */
-function isHandledLogicalOperator(operator) {
-    return operator === "&&" || operator === "||";
-}
-
-/**
- * Gets the label if the parent node of a given node is a LabeledStatement.
- * @param {ASTNode} node A node to get.
- * @returns {string|null} The label or `null`.
- */
-function getLabel(node) {
-    if (node.parent.type === "LabeledStatement") {
-        return node.parent.label.name;
-    }
-    return null;
-}
-
-/**
- * Checks whether or not a given logical expression node goes different path
- * between the `true` case and the `false` case.
- * @param {ASTNode} node A node to check.
- * @returns {boolean} `true` if the node is a test of a choice statement.
- */
-function isForkingByTrueOrFalse(node) {
-    const parent = node.parent;
-
-    switch (parent.type) {
-        case "ConditionalExpression":
-        case "IfStatement":
-        case "WhileStatement":
-        case "DoWhileStatement":
-        case "ForStatement":
-            return parent.test === node;
-
-        case "LogicalExpression":
-            return isHandledLogicalOperator(parent.operator);
-
-        default:
-            return false;
-    }
-}
-
-/**
- * Gets the boolean value of a given literal node.
- *
- * This is used to detect infinity loops (e.g. `while (true) {}`).
- * Statements preceded by an infinity loop are unreachable if the loop didn't
- * have any `break` statement.
- * @param {ASTNode} node A node to get.
- * @returns {boolean|undefined} a boolean value if the node is a Literal node,
- *   otherwise `undefined`.
- */
-function getBooleanValueIfSimpleConstant(node) {
-    if (node.type === "Literal") {
-        return Boolean(node.value);
-    }
-    return void 0;
-}
-
-/**
- * Checks that a given identifier node is a reference or not.
- *
- * This is used to detect the first throwable node in a `try` block.
- * @param {ASTNode} node An Identifier node to check.
- * @returns {boolean} `true` if the node is a reference.
- */
-function isIdentifierReference(node) {
-    const parent = node.parent;
-
-    switch (parent.type) {
-        case "LabeledStatement":
-        case "BreakStatement":
-        case "ContinueStatement":
-        case "ArrayPattern":
-        case "RestElement":
-        case "ImportSpecifier":
-        case "ImportDefaultSpecifier":
-        case "ImportNamespaceSpecifier":
-        case "CatchClause":
-            return false;
-
-        case "FunctionDeclaration":
-        case "FunctionExpression":
-        case "ArrowFunctionExpression":
-        case "ClassDeclaration":
-        case "ClassExpression":
-        case "VariableDeclarator":
-            return parent.id !== node;
-
-        case "Property":
-        case "MethodDefinition":
-            return (
-                parent.key !== node ||
-                parent.computed ||
-                parent.shorthand
-            );
-
-        case "AssignmentPattern":
-            return parent.key !== node;
-
-        default:
-            return true;
-    }
-}
-
-/**
- * Updates the current segment with the head segment.
- * This is similar to local branches and tracking branches of git.
- *
- * To separate the current and the head is in order to not make useless segments.
- *
- * In this process, both "onCodePathSegmentStart" and "onCodePathSegmentEnd"
- * events are fired.
- * @param {CodePathAnalyzer} analyzer The instance.
- * @param {ASTNode} node The current AST node.
- * @returns {void}
- */
-function forwardCurrentToHead(analyzer, node) {
-    const codePath = analyzer.codePath;
-    const state = CodePath.getState(codePath);
-    const currentSegments = state.currentSegments;
-    const headSegments = state.headSegments;
-    const end = Math.max(currentSegments.length, headSegments.length);
-    let i, currentSegment, headSegment;
-
-    // Fires leaving events.
-    for (i = 0; i < end; ++i) {
-        currentSegment = currentSegments[i];
-        headSegment = headSegments[i];
-
-        if (currentSegment !== headSegment && currentSegment) {
-            debug.dump(`onCodePathSegmentEnd ${currentSegment.id}`);
-
-            if (currentSegment.reachable) {
-                analyzer.emitter.emit(
-                    "onCodePathSegmentEnd",
-                    currentSegment,
-                    node
-                );
-            }
-        }
-    }
-
-    // Update state.
-    state.currentSegments = headSegments;
-
-    // Fires entering events.
-    for (i = 0; i < end; ++i) {
-        currentSegment = currentSegments[i];
-        headSegment = headSegments[i];
-
-        if (currentSegment !== headSegment && headSegment) {
-            debug.dump(`onCodePathSegmentStart ${headSegment.id}`);
-
-            CodePathSegment.markUsed(headSegment);
-            if (headSegment.reachable) {
-                analyzer.emitter.emit(
-                    "onCodePathSegmentStart",
-                    headSegment,
-                    node
-                );
-            }
-        }
-    }
-
-}
-
-/**
- * Updates the current segment with empty.
- * This is called at the last of functions or the program.
- * @param {CodePathAnalyzer} analyzer The instance.
- * @param {ASTNode} node The current AST node.
- * @returns {void}
- */
-function leaveFromCurrentSegment(analyzer, node) {
-    const state = CodePath.getState(analyzer.codePath);
-    const currentSegments = state.currentSegments;
-
-    for (let i = 0; i < currentSegments.length; ++i) {
-        const currentSegment = currentSegments[i];
-
-        debug.dump(`onCodePathSegmentEnd ${currentSegment.id}`);
-        if (currentSegment.reachable) {
-            analyzer.emitter.emit(
-                "onCodePathSegmentEnd",
-                currentSegment,
-                node
-            );
-        }
-    }
-
-    state.currentSegments = [];
-}
-
-/**
- * Updates the code path due to the position of a given node in the parent node
- * thereof.
- *
- * For example, if the node is `parent.consequent`, this creates a fork from the
- * current path.
- * @param {CodePathAnalyzer} analyzer The instance.
- * @param {ASTNode} node The current AST node.
- * @returns {void}
- */
-function preprocess(analyzer, node) {
-    const codePath = analyzer.codePath;
-    const state = CodePath.getState(codePath);
-    const parent = node.parent;
-
-    switch (parent.type) {
-        case "LogicalExpression":
-            if (
-                parent.right === node &&
-                isHandledLogicalOperator(parent.operator)
-            ) {
-                state.makeLogicalRight();
-            }
-            break;
-
-        case "ConditionalExpression":
-        case "IfStatement":
-
-            /*
-             * Fork if this node is at `consequent`/`alternate`.
-             * `popForkContext()` exists at `IfStatement:exit` and
-             * `ConditionalExpression:exit`.
-             */
-            if (parent.consequent === node) {
-                state.makeIfConsequent();
-            } else if (parent.alternate === node) {
-                state.makeIfAlternate();
-            }
-            break;
-
-        case "SwitchCase":
-            if (parent.consequent[0] === node) {
-                state.makeSwitchCaseBody(false, !parent.test);
-            }
-            break;
-
-        case "TryStatement":
-            if (parent.handler === node) {
-                state.makeCatchBlock();
-            } else if (parent.finalizer === node) {
-                state.makeFinallyBlock();
-            }
-            break;
-
-        case "WhileStatement":
-            if (parent.test === node) {
-                state.makeWhileTest(getBooleanValueIfSimpleConstant(node));
-            } else {
-                assert(parent.body === node);
-                state.makeWhileBody();
-            }
-            break;
-
-        case "DoWhileStatement":
-            if (parent.body === node) {
-                state.makeDoWhileBody();
-            } else {
-                assert(parent.test === node);
-                state.makeDoWhileTest(getBooleanValueIfSimpleConstant(node));
-            }
-            break;
-
-        case "ForStatement":
-            if (parent.test === node) {
-                state.makeForTest(getBooleanValueIfSimpleConstant(node));
-            } else if (parent.update === node) {
-                state.makeForUpdate();
-            } else if (parent.body === node) {
-                state.makeForBody();
-            }
-            break;
-
-        case "ForInStatement":
-        case "ForOfStatement":
-            if (parent.left === node) {
-                state.makeForInOfLeft();
-            } else if (parent.right === node) {
-                state.makeForInOfRight();
-            } else {
-                assert(parent.body === node);
-                state.makeForInOfBody();
-            }
-            break;
-
-        case "AssignmentPattern":
-
-            /*
-             * Fork if this node is at `right`.
-             * `left` is executed always, so it uses the current path.
-             * `popForkContext()` exists at `AssignmentPattern:exit`.
-             */
-            if (parent.right === node) {
-                state.pushForkContext();
-                state.forkBypassPath();
-                state.forkPath();
-            }
-            break;
-
-        default:
-            break;
-    }
-}
-
-/**
- * Updates the code path due to the type of a given node in entering.
- * @param {CodePathAnalyzer} analyzer The instance.
- * @param {ASTNode} node The current AST node.
- * @returns {void}
- */
-function processCodePathToEnter(analyzer, node) {
-    let codePath = analyzer.codePath;
-    let state = codePath && CodePath.getState(codePath);
-    const parent = node.parent;
-
-    switch (node.type) {
-        case "Program":
-        case "FunctionDeclaration":
-        case "FunctionExpression":
-        case "ArrowFunctionExpression":
-            if (codePath) {
-
-                // Emits onCodePathSegmentStart events if updated.
-                forwardCurrentToHead(analyzer, node);
-                debug.dumpState(node, state, false);
-            }
-
-            // Create the code path of this scope.
-            codePath = analyzer.codePath = new CodePath(
-                analyzer.idGenerator.next(),
-                codePath,
-                analyzer.onLooped
-            );
-            state = CodePath.getState(codePath);
-
-            // Emits onCodePathStart events.
-            debug.dump(`onCodePathStart ${codePath.id}`);
-            analyzer.emitter.emit("onCodePathStart", codePath, node);
-            break;
-
-        case "LogicalExpression":
-            if (isHandledLogicalOperator(node.operator)) {
-                state.pushChoiceContext(
-                    node.operator,
-                    isForkingByTrueOrFalse(node)
-                );
-            }
-            break;
-
-        case "ConditionalExpression":
-        case "IfStatement":
-            state.pushChoiceContext("test", false);
-            break;
-
-        case "SwitchStatement":
-            state.pushSwitchContext(
-                node.cases.some(isCaseNode),
-                getLabel(node)
-            );
-            break;
-
-        case "TryStatement":
-            state.pushTryContext(Boolean(node.finalizer));
-            break;
-
-        case "SwitchCase":
-
-            /*
-             * Fork if this node is after the 2st node in `cases`.
-             * It's similar to `else` blocks.
-             * The next `test` node is processed in this path.
-             */
-            if (parent.discriminant !== node && parent.cases[0] !== node) {
-                state.forkPath();
-            }
-            break;
-
-        case "WhileStatement":
-        case "DoWhileStatement":
-        case "ForStatement":
-        case "ForInStatement":
-        case "ForOfStatement":
-            state.pushLoopContext(node.type, getLabel(node));
-            break;
-
-        case "LabeledStatement":
-            if (!breakableTypePattern.test(node.body.type)) {
-                state.pushBreakContext(false, node.label.name);
-            }
-            break;
-
-        default:
-            break;
-    }
-
-    // Emits onCodePathSegmentStart events if updated.
-    forwardCurrentToHead(analyzer, node);
-    debug.dumpState(node, state, false);
-}
-
-/**
- * Updates the code path due to the type of a given node in leaving.
- * @param {CodePathAnalyzer} analyzer The instance.
- * @param {ASTNode} node The current AST node.
- * @returns {void}
- */
-function processCodePathToExit(analyzer, node) {
-    const codePath = analyzer.codePath;
-    const state = CodePath.getState(codePath);
-    let dontForward = false;
-
-    switch (node.type) {
-        case "IfStatement":
-        case "ConditionalExpression":
-            state.popChoiceContext();
-            break;
-
-        case "LogicalExpression":
-            if (isHandledLogicalOperator(node.operator)) {
-                state.popChoiceContext();
-            }
-            break;
-
-        case "SwitchStatement":
-            state.popSwitchContext();
-            break;
-
-        case "SwitchCase":
-
-            /*
-             * This is the same as the process at the 1st `consequent` node in
-             * `preprocess` function.
-             * Must do if this `consequent` is empty.
-             */
-            if (node.consequent.length === 0) {
-                state.makeSwitchCaseBody(true, !node.test);
-            }
-            if (state.forkContext.reachable) {
-                dontForward = true;
-            }
-            break;
-
-        case "TryStatement":
-            state.popTryContext();
-            break;
-
-        case "BreakStatement":
-            forwardCurrentToHead(analyzer, node);
-            state.makeBreak(node.label && node.label.name);
-            dontForward = true;
-            break;
-
-        case "ContinueStatement":
-            forwardCurrentToHead(analyzer, node);
-            state.makeContinue(node.label && node.label.name);
-            dontForward = true;
-            break;
-
-        case "ReturnStatement":
-            forwardCurrentToHead(analyzer, node);
-            state.makeReturn();
-            dontForward = true;
-            break;
-
-        case "ThrowStatement":
-            forwardCurrentToHead(analyzer, node);
-            state.makeThrow();
-            dontForward = true;
-            break;
-
-        case "Identifier":
-            if (isIdentifierReference(node)) {
-                state.makeFirstThrowablePathInTryBlock();
-                dontForward = true;
-            }
-            break;
-
-        case "CallExpression":
-        case "ImportExpression":
-        case "MemberExpression":
-        case "NewExpression":
-            state.makeFirstThrowablePathInTryBlock();
-            break;
-
-        case "WhileStatement":
-        case "DoWhileStatement":
-        case "ForStatement":
-        case "ForInStatement":
-        case "ForOfStatement":
-            state.popLoopContext();
-            break;
-
-        case "AssignmentPattern":
-            state.popForkContext();
-            break;
-
-        case "LabeledStatement":
-            if (!breakableTypePattern.test(node.body.type)) {
-                state.popBreakContext();
-            }
-            break;
-
-        default:
-            break;
-    }
-
-    // Emits onCodePathSegmentStart events if updated.
-    if (!dontForward) {
-        forwardCurrentToHead(analyzer, node);
-    }
-    debug.dumpState(node, state, true);
-}
-
-/**
- * Updates the code path to finalize the current code path.
- * @param {CodePathAnalyzer} analyzer The instance.
- * @param {ASTNode} node The current AST node.
- * @returns {void}
- */
-function postprocess(analyzer, node) {
-    switch (node.type) {
-        case "Program":
-        case "FunctionDeclaration":
-        case "FunctionExpression":
-        case "ArrowFunctionExpression": {
-            let codePath = analyzer.codePath;
-
-            // Mark the current path as the final node.
-            CodePath.getState(codePath).makeFinal();
-
-            // Emits onCodePathSegmentEnd event of the current segments.
-            leaveFromCurrentSegment(analyzer, node);
-
-            // Emits onCodePathEnd event of this code path.
-            debug.dump(`onCodePathEnd ${codePath.id}`);
-            analyzer.emitter.emit("onCodePathEnd", codePath, node);
-            debug.dumpDot(codePath);
-
-            codePath = analyzer.codePath = analyzer.codePath.upper;
-            if (codePath) {
-                debug.dumpState(node, CodePath.getState(codePath), true);
-            }
-            break;
-        }
-
-        default:
-            break;
-    }
-}
-
-//------------------------------------------------------------------------------
-// Public Interface
-//------------------------------------------------------------------------------
-
-/**
- * The class to analyze code paths.
- * This class implements the EventGenerator interface.
- */
-class CodePathAnalyzer {
-
-    // eslint-disable-next-line jsdoc/require-description
-    /**
-     * @param {EventGenerator} eventGenerator An event generator to wrap.
-     */
-    constructor(eventGenerator) {
-        this.original = eventGenerator;
-        this.emitter = eventGenerator.emitter;
-        this.codePath = null;
-        this.idGenerator = new IdGenerator("s");
-        this.currentNode = null;
-        this.onLooped = this.onLooped.bind(this);
-    }
-
-    /**
-     * Does the process to enter a given AST node.
-     * This updates state of analysis and calls `enterNode` of the wrapped.
-     * @param {ASTNode} node A node which is entering.
-     * @returns {void}
-     */
-    enterNode(node) {
-        this.currentNode = node;
-
-        // Updates the code path due to node's position in its parent node.
-        if (node.parent) {
-            preprocess(this, node);
-        }
-
-        /*
-         * Updates the code path.
-         * And emits onCodePathStart/onCodePathSegmentStart events.
-         */
-        processCodePathToEnter(this, node);
-
-        // Emits node events.
-        this.original.enterNode(node);
-
-        this.currentNode = null;
-    }
-
-    /**
-     * Does the process to leave a given AST node.
-     * This updates state of analysis and calls `leaveNode` of the wrapped.
-     * @param {ASTNode} node A node which is leaving.
-     * @returns {void}
-     */
-    leaveNode(node) {
-        this.currentNode = node;
-
-        /*
-         * Updates the code path.
-         * And emits onCodePathStart/onCodePathSegmentStart events.
-         */
-        processCodePathToExit(this, node);
-
-        // Emits node events.
-        this.original.leaveNode(node);
-
-        // Emits the last onCodePathStart/onCodePathSegmentStart events.
-        postprocess(this, node);
-
-        this.currentNode = null;
-    }
-
-    /**
-     * This is called on a code path looped.
-     * Then this raises a looped event.
-     * @param {CodePathSegment} fromSegment A segment of prev.
-     * @param {CodePathSegment} toSegment A segment of next.
-     * @returns {void}
-     */
-    onLooped(fromSegment, toSegment) {
-        if (fromSegment.reachable && toSegment.reachable) {
-            debug.dump(`onCodePathSegmentLoop ${fromSegment.id} -> ${toSegment.id}`);
-            this.emitter.emit(
-                "onCodePathSegmentLoop",
-                fromSegment,
-                toSegment,
-                this.currentNode
-            );
-        }
-    }
-}
-
-module.exports = CodePathAnalyzer;