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

dead_code lint highlights too much on functions with multi-line signatures #63064

Closed
alvinhochun opened this issue Jul 28, 2019 · 5 comments
Closed
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@alvinhochun
Copy link

With the following example code:

fn unused() {
    println!("blah");
}

fn unused2(var: i32) {
    println!("foo {}", var);
}

fn unused3(
    var: i32,
) {
    println!("bar {}", var);
}

fn main() {
    println!("Hello world!");
}

(Playground)

The compiler produces these warnings:

warning: function is never used: `unused`
 --> src/main.rs:1:1
  |
1 | fn unused() {
  | ^^^^^^^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: function is never used: `unused2`
 --> src/main.rs:5:1
  |
5 | fn unused2(var: i32) {
  | ^^^^^^^^^^^^^^^^^^^^

warning: function is never used: `unused3`
  --> src/main.rs:9:1
   |
9  | / fn unused3(
10 | |     var: i32,
11 | | ) {
12 | |     println!("bar {}", var);
13 | | }
   | |_^

Notice that for fn unused and fn unused2, dead_code is reported on only the first line signature of the function, however for fn unused3 dead_code is reported on the whole function from start to finish.

This is mostly annoying when writing new functions in an editor like vscode that rls will cause the whole function to be orange-wavy-underlined, making a huge distraction.

@jakubadamw
Copy link
Contributor

I've seen this as well.

It's been years since I hacked on the compiler, so I'll claim this as a bug to fix so as to refresh my memory of what's where. :)

@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 28, 2019
@estebank
Copy link
Contributor

estebank commented Jul 29, 2019

There's a method SourceMap::def_span that explicitly looks for the next { token. If the resulting span is a single line, it uses that, otherwise it uses the full span under the assumption that the multiline span would look weird:

warning: function is never used: `unused3`
  --> src/main.rs:9:1
   |
9  | / fn unused3(
10 | |     var: i32,
11 | | ) {
   | |_^

With that, most of the places where we are calling def_span could be changed so that they get the Ident for the function and use its span instead (we used not to encode Spans in Idents due to size concerns). With this change, the resulting output would be:

warning: function is never used: `unused`
 --> src/main.rs:1:1
  |
1 | fn unused() {
  |    ^^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: function is never used: `unused2`
 --> src/main.rs:5:1
  |
5 | fn unused2(var: i32) {
  |    ^^^^^^^

warning: function is never used: `unused3`
  --> src/main.rs:9:1
   |
9  | fn unused3(
   |    ^^^^^^^

The reason I haven't pushed for that change is because in some cases the extra information from the other lines is useful to give context, but for errors like this one we just need to identify the function and nothing more.

@jakubadamw
Copy link
Contributor

jakubadamw commented Jul 29, 2019

@estebank, thanks for explaining. This would be in line with what I'd already figured. 🙂 By the way, that function assumes that items would have a leading { in their definition, whereas that's not the case for top-level modules. I filed #63091 with an example of that breaking (and that's regardless of whether this gets fixed).

@jakubadamw
Copy link
Contributor

Oh, this has been reported before: #58729.

@estebank
Copy link
Contributor

estebank commented Aug 6, 2019

Closing as duplicate of #58729

@estebank estebank closed this as completed Aug 6, 2019
Centril added a commit to Centril/rust that referenced this issue Oct 26, 2019
Use ident.span instead of def_span in dead-code pass

Hello! First time contributor! :)

This should fix rust-lang#58729.

According to @estebank in the duplicate rust-lang#63064, def_span scans forward on the line until it finds a {,
and if it can't find one, falls back to the span for the whole item. This
was apparently written before the identifier span was explicitly tracked on
each node.

This means that if an unused function signature spans multiple lines, the
entire function (potentially hundreds of lines) gets flagged as dead code.
This could, for example, cause IDEs to add error squiggly's to the whole
function.

By using the span from the ident instead, we narrow the scope of this in
most cases. In a wider sense, it's probably safe to use ident.span
instead of def_span in most locations throughout the whole code base,
but since this is my first contribution, I kept it small.

Some interesting points that came up while I was working on this:
- I reorganized the tests a bit to bring some of the dead code ones all
into the same location
- A few tests were for things unrelated to dead code (like the
path-lookahead for parens), so I added #![allow(dead_code)] and
cleaned up the stderr file to reduce noise in the future
- The same fix doesn't apply to const and static declarations. I tried
adding these cases to the match expression, but that created a much
wider change to tests and error messages, so I left it off until I
could get some code review to validate the approach.
Centril added a commit to Centril/rust that referenced this issue Oct 26, 2019
Use ident.span instead of def_span in dead-code pass

Hello! First time contributor! :)

This should fix rust-lang#58729.

According to @estebank in the duplicate rust-lang#63064, def_span scans forward on the line until it finds a {,
and if it can't find one, falls back to the span for the whole item. This
was apparently written before the identifier span was explicitly tracked on
each node.

This means that if an unused function signature spans multiple lines, the
entire function (potentially hundreds of lines) gets flagged as dead code.
This could, for example, cause IDEs to add error squiggly's to the whole
function.

By using the span from the ident instead, we narrow the scope of this in
most cases. In a wider sense, it's probably safe to use ident.span
instead of def_span in most locations throughout the whole code base,
but since this is my first contribution, I kept it small.

Some interesting points that came up while I was working on this:
- I reorganized the tests a bit to bring some of the dead code ones all
into the same location
- A few tests were for things unrelated to dead code (like the
path-lookahead for parens), so I added #![allow(dead_code)] and
cleaned up the stderr file to reduce noise in the future
- The same fix doesn't apply to const and static declarations. I tried
adding these cases to the match expression, but that created a much
wider change to tests and error messages, so I left it off until I
could get some code review to validate the approach.
bors added a commit that referenced this issue Nov 6, 2019
Use ident.span instead of def_span in dead-code pass

Hello! First time contributor! :)

This should fix #58729.

According to @estebank in the duplicate #63064, def_span scans forward on the line until it finds a {,
and if it can't find one, falls back to the span for the whole item. This
was apparently written before the identifier span was explicitly tracked on
each node.

This means that if an unused function signature spans multiple lines, the
entire function (potentially hundreds of lines) gets flagged as dead code.
This could, for example, cause IDEs to add error squiggly's to the whole
function.

By using the span from the ident instead, we narrow the scope of this in
most cases. In a wider sense, it's probably safe to use ident.span
instead of def_span in most locations throughout the whole code base,
but since this is my first contribution, I kept it small.

Some interesting points that came up while I was working on this:
- I reorganized the tests a bit to bring some of the dead code ones all
into the same location
- A few tests were for things unrelated to dead code (like the
path-lookahead for parens), so I added #![allow(dead_code)] and
cleaned up the stderr file to reduce noise in the future
- The same fix doesn't apply to const and static declarations. I tried
adding these cases to the match expression, but that created a much
wider change to tests and error messages, so I left it off until I
could get some code review to validate the approach.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants