quick-lint-js icon indicating copy to clipboard operation
quick-lint-js copied to clipboard

20$: Detect dead code and unused variables

Open strager opened this issue 2 years ago • 10 comments

Create a special diagnostic for dead code and unused variables.

Example:

function f() {
  let x = 69;  // info: unused variable
  return 42;
  g();         // info: unreachable code
}

In editors, these diagnostics should be enabled by default. LSP has DiagnosticTag.Unnecessary, and VS Code probably has an API too.

In the CLI, these diagnostics should be opt-in, or not part of the exit-fail-on set.

(This might need to be split into two or three tasks.)

strager avatar May 03 '22 08:05 strager

Another example of redundant code: continue at the end of a loop:

for (let b of bananas) {
  console.log(b);
  continue;        // redundant
}

strager avatar Jun 02 '22 17:06 strager

Another example of redundant code: true&& and false||:

&&true is not entirely redundant though:

> true && "x"
'x'
> false || "x"
'x'
> "x" && true  // <--
true
> "x" || false
'x'

Same with || false:

> true && null
null
> false || null
null
> null && true
null
> null || false  // <--
false

strager avatar Jun 02 '22 17:06 strager

Another example: x === y ? true : false

strager avatar Jun 02 '22 18:06 strager

Another example: returning undefined explicitly at the end of a function:

function f() {
  console.log("hi");
  return;             // redundant
}

strager avatar Jun 02 '22 18:06 strager

Another example: chained TypeScript null assertions:

let x: int? = 42;
console.log(x!!!);
//            ^^ redundant

strager avatar Jun 02 '22 18:06 strager

Another example: empty export statements:

export {};  // redundant

strager avatar Jun 02 '22 18:06 strager

Another example: final assignment to a local variable which isn't later referenced:

let x = 42;
x = 69;      // warning

strager avatar Jun 02 '22 18:06 strager

Another example: self-assignment for local variables:

let x = 1, y = 2;
x = x;  // warning

strager avatar Jun 02 '22 18:06 strager

Another example: return with value in a setter:

class C {
  get x() { return this._x; }
  set x(v) {
    this._x = v;
    return v;  // warning
  }
}

strager avatar Jun 02 '22 18:06 strager

More examples in TypeScript:

x!!       // second ! is redundant
x!?.prop  // ? is redundant
x!?.()    // ?. is redundant

strager avatar Jun 23 '22 08:06 strager

C will never get executed in the following code, so we should mark it as dead code:

for (A; B; C) {
  D;
  return E;
}

strager avatar Mar 18 '23 02:03 strager