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
This commit is contained in:
commit
ed6d17523a
4 changed files with 151 additions and 29 deletions
|
@ -4150,34 +4150,36 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"),
|
||||
};
|
||||
|
||||
if path.len() > 1
|
||||
&& let Some(res) = result.full_res()
|
||||
&& let Some((&last_segment, prev_segs)) = path.split_last()
|
||||
&& prev_segs.iter().all(|seg| !seg.has_generic_args)
|
||||
&& res != Res::Err
|
||||
&& path[0].ident.name != kw::PathRoot
|
||||
&& path[0].ident.name != kw::DollarCrate
|
||||
{
|
||||
let unqualified_result = {
|
||||
match self.resolve_path(&[last_segment], Some(ns), None) {
|
||||
PathResult::NonModule(path_res) => path_res.expect_full_res(),
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
|
||||
module.res().unwrap()
|
||||
}
|
||||
_ => return Ok(Some(result)),
|
||||
}
|
||||
};
|
||||
if res == unqualified_result {
|
||||
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
|
||||
if path.iter().all(|seg| !seg.ident.span.from_expansion()) {
|
||||
let end_pos =
|
||||
path.iter().position(|seg| seg.has_generic_args).map_or(path.len(), |pos| pos + 1);
|
||||
let unqualified =
|
||||
path[..end_pos].iter().enumerate().skip(1).rev().find_map(|(i, seg)| {
|
||||
// Preserve the current namespace for the final path segment, but use the type
|
||||
// namespace for all preceding segments
|
||||
//
|
||||
// e.g. for `std::env::args` check the `ValueNS` for `args` but the `TypeNS` for
|
||||
// `std` and `env`
|
||||
//
|
||||
// If the final path segment is beyond `end_pos` all the segments to check will
|
||||
// use the type namespace
|
||||
let ns = if i + 1 == path.len() { ns } else { TypeNS };
|
||||
let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?;
|
||||
let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?;
|
||||
|
||||
(res == binding.res()).then_some(seg)
|
||||
});
|
||||
|
||||
if let Some(unqualified) = unqualified {
|
||||
self.r.lint_buffer.buffer_lint_with_diagnostic(
|
||||
lint,
|
||||
lint::builtin::UNUSED_QUALIFICATIONS,
|
||||
finalize.node_id,
|
||||
finalize.path_span,
|
||||
"unnecessary qualification",
|
||||
lint::BuiltinLintDiagnostics::UnusedQualifications {
|
||||
removal_span: finalize.path_span.until(last_segment.ident.span),
|
||||
removal_span: finalize.path_span.until(unqualified.ident.span),
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue