Skip to content

Commit ed6d175

Browse files
authored
Rollup merge of #121528 - Alexendoo:unused_qualifications, r=petrochenkov
Consider middle segments of paths in `unused_qualifications` Currently `unused_qualifications` looks at the last segment of a path to see if it can be trimmed, this PR extends the check to the middle segments also ```rust // currently linted use std::env::args(); std::env::args(); // Removes `std::env::` ``` ```rust // newly linted use std::env; std::env::args(); // Removes `std::` ``` Paths with generics in them are now linted as long as the part being trimmed is before any generic args, e.g. it will now suggest trimming `std::vec::` from `std::vec::Vec<usize>` Paths with any segments that are from an expansion are no longer linted Fixes #100979 Fixes #96698
2 parents d37ad03 + 4ea9f72 commit ed6d175

File tree

4 files changed

+151
-29
lines changed

4 files changed

+151
-29
lines changed

compiler/rustc_resolve/src/late.rs

+24-22
Original file line numberDiff line numberDiff line change
@@ -4150,34 +4150,36 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
41504150
PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"),
41514151
};
41524152

4153-
if path.len() > 1
4154-
&& let Some(res) = result.full_res()
4155-
&& let Some((&last_segment, prev_segs)) = path.split_last()
4156-
&& prev_segs.iter().all(|seg| !seg.has_generic_args)
4157-
&& res != Res::Err
4158-
&& path[0].ident.name != kw::PathRoot
4159-
&& path[0].ident.name != kw::DollarCrate
4160-
{
4161-
let unqualified_result = {
4162-
match self.resolve_path(&[last_segment], Some(ns), None) {
4163-
PathResult::NonModule(path_res) => path_res.expect_full_res(),
4164-
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
4165-
module.res().unwrap()
4166-
}
4167-
_ => return Ok(Some(result)),
4168-
}
4169-
};
4170-
if res == unqualified_result {
4171-
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
4153+
if path.iter().all(|seg| !seg.ident.span.from_expansion()) {
4154+
let end_pos =
4155+
path.iter().position(|seg| seg.has_generic_args).map_or(path.len(), |pos| pos + 1);
4156+
let unqualified =
4157+
path[..end_pos].iter().enumerate().skip(1).rev().find_map(|(i, seg)| {
4158+
// Preserve the current namespace for the final path segment, but use the type
4159+
// namespace for all preceding segments
4160+
//
4161+
// e.g. for `std::env::args` check the `ValueNS` for `args` but the `TypeNS` for
4162+
// `std` and `env`
4163+
//
4164+
// If the final path segment is beyond `end_pos` all the segments to check will
4165+
// use the type namespace
4166+
let ns = if i + 1 == path.len() { ns } else { TypeNS };
4167+
let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?;
4168+
let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?;
4169+
4170+
(res == binding.res()).then_some(seg)
4171+
});
4172+
4173+
if let Some(unqualified) = unqualified {
41724174
self.r.lint_buffer.buffer_lint_with_diagnostic(
4173-
lint,
4175+
lint::builtin::UNUSED_QUALIFICATIONS,
41744176
finalize.node_id,
41754177
finalize.path_span,
41764178
"unnecessary qualification",
41774179
lint::BuiltinLintDiagnostics::UnusedQualifications {
4178-
removal_span: finalize.path_span.until(last_segment.ident.span),
4180+
removal_span: finalize.path_span.until(unqualified.ident.span),
41794181
},
4180-
)
4182+
);
41814183
}
41824184
}
41834185

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ run-rustfix
22
#![deny(unused_qualifications)]
3-
#![allow(deprecated)]
3+
#![allow(deprecated, dead_code)]
44

55
mod foo {
66
pub fn bar() {}
@@ -9,13 +9,37 @@ mod foo {
99
fn main() {
1010
use foo::bar;
1111
bar(); //~ ERROR: unnecessary qualification
12+
bar(); //~ ERROR: unnecessary qualification
1213
bar();
1314

1415
let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345
1516

16-
macro_rules! m { () => {
17+
let _ = String::new(); //~ ERROR: unnecessary qualification
18+
let _ = std::env::current_dir(); //~ ERROR: unnecessary qualification
19+
20+
let _: Vec<String> = Vec::<String>::new();
21+
//~^ ERROR: unnecessary qualification
22+
//~| ERROR: unnecessary qualification
23+
24+
use std::fmt;
25+
let _: fmt::Result = Ok(()); //~ ERROR: unnecessary qualification
26+
27+
macro_rules! m { ($a:ident, $b:ident) => {
1728
$crate::foo::bar(); // issue #37357
1829
::foo::bar(); // issue #38682
30+
foo::bar();
31+
foo::$b(); // issue #96698
32+
$a::bar();
1933
} }
20-
m!();
34+
m!(foo, bar);
35+
}
36+
37+
mod conflicting_names {
38+
mod std {}
39+
mod cell {}
40+
41+
fn f() {
42+
let _ = ::std::env::current_dir();
43+
let _ = core::cell::Cell::new(1);
44+
}
2145
}

tests/ui/lint/lint-qualification.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ run-rustfix
22
#![deny(unused_qualifications)]
3-
#![allow(deprecated)]
3+
#![allow(deprecated, dead_code)]
44

55
mod foo {
66
pub fn bar() {}
@@ -9,13 +9,37 @@ mod foo {
99
fn main() {
1010
use foo::bar;
1111
foo::bar(); //~ ERROR: unnecessary qualification
12+
crate::foo::bar(); //~ ERROR: unnecessary qualification
1213
bar();
1314

1415
let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345
1516

16-
macro_rules! m { () => {
17+
let _ = std::string::String::new(); //~ ERROR: unnecessary qualification
18+
let _ = ::std::env::current_dir(); //~ ERROR: unnecessary qualification
19+
20+
let _: std::vec::Vec<String> = std::vec::Vec::<String>::new();
21+
//~^ ERROR: unnecessary qualification
22+
//~| ERROR: unnecessary qualification
23+
24+
use std::fmt;
25+
let _: std::fmt::Result = Ok(()); //~ ERROR: unnecessary qualification
26+
27+
macro_rules! m { ($a:ident, $b:ident) => {
1728
$crate::foo::bar(); // issue #37357
1829
::foo::bar(); // issue #38682
30+
foo::bar();
31+
foo::$b(); // issue #96698
32+
$a::bar();
1933
} }
20-
m!();
34+
m!(foo, bar);
35+
}
36+
37+
mod conflicting_names {
38+
mod std {}
39+
mod cell {}
40+
41+
fn f() {
42+
let _ = ::std::env::current_dir();
43+
let _ = core::cell::Cell::new(1);
44+
}
2145
}

tests/ui/lint/lint-qualification.stderr

+73-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,77 @@ LL - foo::bar();
1515
LL + bar();
1616
|
1717

18-
error: aborting due to 1 previous error
18+
error: unnecessary qualification
19+
--> $DIR/lint-qualification.rs:12:5
20+
|
21+
LL | crate::foo::bar();
22+
| ^^^^^^^^^^^^^^^
23+
|
24+
help: remove the unnecessary path segments
25+
|
26+
LL - crate::foo::bar();
27+
LL + bar();
28+
|
29+
30+
error: unnecessary qualification
31+
--> $DIR/lint-qualification.rs:17:13
32+
|
33+
LL | let _ = std::string::String::new();
34+
| ^^^^^^^^^^^^^^^^^^^^^^^^
35+
|
36+
help: remove the unnecessary path segments
37+
|
38+
LL - let _ = std::string::String::new();
39+
LL + let _ = String::new();
40+
|
41+
42+
error: unnecessary qualification
43+
--> $DIR/lint-qualification.rs:18:13
44+
|
45+
LL | let _ = ::std::env::current_dir();
46+
| ^^^^^^^^^^^^^^^^^^^^^^^
47+
|
48+
help: remove the unnecessary path segments
49+
|
50+
LL - let _ = ::std::env::current_dir();
51+
LL + let _ = std::env::current_dir();
52+
|
53+
54+
error: unnecessary qualification
55+
--> $DIR/lint-qualification.rs:20:12
56+
|
57+
LL | let _: std::vec::Vec<String> = std::vec::Vec::<String>::new();
58+
| ^^^^^^^^^^^^^^^^^^^^^
59+
|
60+
help: remove the unnecessary path segments
61+
|
62+
LL - let _: std::vec::Vec<String> = std::vec::Vec::<String>::new();
63+
LL + let _: Vec<String> = std::vec::Vec::<String>::new();
64+
|
65+
66+
error: unnecessary qualification
67+
--> $DIR/lint-qualification.rs:20:36
68+
|
69+
LL | let _: std::vec::Vec<String> = std::vec::Vec::<String>::new();
70+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
71+
|
72+
help: remove the unnecessary path segments
73+
|
74+
LL - let _: std::vec::Vec<String> = std::vec::Vec::<String>::new();
75+
LL + let _: std::vec::Vec<String> = Vec::<String>::new();
76+
|
77+
78+
error: unnecessary qualification
79+
--> $DIR/lint-qualification.rs:25:12
80+
|
81+
LL | let _: std::fmt::Result = Ok(());
82+
| ^^^^^^^^^^^^^^^^
83+
|
84+
help: remove the unnecessary path segments
85+
|
86+
LL - let _: std::fmt::Result = Ok(());
87+
LL + let _: fmt::Result = Ok(());
88+
|
89+
90+
error: aborting due to 7 previous errors
1991

0 commit comments

Comments
 (0)