• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* @internal */
2namespace ts.codefix {
3    const fixId = "fixUnreachableCode";
4    const errorCodes = [Diagnostics.Unreachable_code_detected.code];
5    registerCodeFix({
6        errorCodes,
7        getCodeActions(context) {
8            const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.span.length, context.errorCode));
9            return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unreachable_code, fixId, Diagnostics.Remove_all_unreachable_code)];
10        },
11        fixIds: [fixId],
12        getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start, diag.length, diag.code)),
13    });
14
15    function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number, length: number, errorCode: number): void {
16        const token = getTokenAtPosition(sourceFile, start);
17        const statement = findAncestor(token, isStatement)!;
18        if (statement.getStart(sourceFile) !== token.getStart(sourceFile)) {
19            const logData = JSON.stringify({
20                statementKind: Debug.formatSyntaxKind(statement.kind),
21                tokenKind: Debug.formatSyntaxKind(token.kind),
22                errorCode,
23                start,
24                length
25            });
26            Debug.fail("Token and statement should start at the same point. " + logData);
27        }
28
29        const container = (isBlock(statement.parent) ? statement.parent : statement).parent;
30        if (!isBlock(statement.parent) || statement === first(statement.parent.statements)) {
31            switch (container.kind) {
32                case SyntaxKind.IfStatement:
33                    if ((container as IfStatement).elseStatement) {
34                        if (isBlock(statement.parent)) {
35                            break;
36                        }
37                        else {
38                            changes.replaceNode(sourceFile, statement, factory.createBlock(emptyArray));
39                        }
40                        return;
41                    }
42                    // falls through
43                case SyntaxKind.WhileStatement:
44                case SyntaxKind.ForStatement:
45                    changes.delete(sourceFile, container);
46                    return;
47            }
48        }
49
50        if (isBlock(statement.parent)) {
51            const end = start + length;
52            const lastStatement = Debug.checkDefined(lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end), "Some statement should be last");
53            changes.deleteNodeRange(sourceFile, statement, lastStatement);
54        }
55        else {
56            changes.delete(sourceFile, statement);
57        }
58    }
59
60    function lastWhere<T>(a: readonly T[], pred: (value: T) => boolean): T | undefined {
61        let last: T | undefined;
62        for (const value of a) {
63            if (!pred(value)) break;
64            last = value;
65        }
66        return last;
67    }
68}
69