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