Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add code fix to remove unreachable code #24028

Merged
4 commits merged into from
May 10, 2018
Merged

Add code fix to remove unreachable code #24028

4 commits merged into from
May 10, 2018

Conversation

ghost
Copy link

@ghost ghost commented May 10, 2018

Mentioned in #24026

@ghost ghost requested review from mhegazy and amcasey May 10, 2018 17:21
@ghost ghost force-pushed the codeFixUnreachableCode branch from 7b9ac54 to 539a43d Compare May 10, 2018 17:26
@ghost ghost force-pushed the codeFixUnreachableCode branch from 539a43d to 88b7948 Compare May 10, 2018 17:27
const container = (isBlock(statement.parent) ? statement.parent : statement).parent;
switch (container.kind) {
case SyntaxKind.IfStatement:
return (container as IfStatement).elseStatement ? statement : container as IfStatement;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the statement was not in a block, that will leave the the ifStatement syntactically incorrect.. e.g.

    if (false) console.log();
    else console.log();
case SyntaxKind.ForStatement:
return container as WhileStatement | ForStatement;
default:
return statement;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you want to return all statemetns from this one untill the end of the block, e.g.:

function f() { 
   return 0;

  // both should be removed, error is only on the first.
   var x = 0;
   console.log(x);
}
break;
default:
if (isBlock(statement.parent)) {
split(sliceAfter(statement.parent.statements, statement), s => !isFunctionDeclaration(s), (start, end) => changes.deleteNodeRange(sourceFile, start, end));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably also want to preserve type alias declarations, interfaces, const enums, type only namespaces, var statements, ...

@ghost ghost mentioned this pull request May 10, 2018
// Don't remove statements that can validly be used before they appear.
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
// `var x;` may declare a variable used above
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
Copy link
Contributor

@mhegazy mhegazy May 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it is a var statement it make sure it is not ambient.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's ambient, it should not have an initializer so we won't remove it, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

declare let x; would be removed, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right.
Actually, I can't think of a way a declare statement would be unreachable?

@ghost ghost merged commit 6ae4d3a into master May 10, 2018
@ghost ghost deleted the codeFixUnreachableCode branch May 10, 2018 23:44
Copy link
Member

@amcasey amcasey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions.

newFileContent:
`
// No good way to delete just the 'if' part
if (false) { } else b;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a perfect world, the output would be b;?

case SyntaxKind.IfStatement:
if ((container as IfStatement).elseStatement) {
if (isBlock(statement.parent)) {
changes.deleteNodeRange(sourceFile, first(statement.parent.statements), last(statement.parent.statements));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to eliminate the whole else-clause?

}

function shouldRemove(s: Statement): boolean {
// Don't remove statements that can validly be used before they appear.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm missing something - why would it be reported as unused if it's used above?

split(sliceAfter(statement.parent.statements, statement), shouldRemove, (start, end) => changes.deleteNodeRange(sourceFile, start, end));
}
else {
changes.deleteNode(sourceFile, statement);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will a switch case ever be reported as unused? Does that need special handling? What about a catch block?

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
3 participants