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