diff options
| author | Felix S. Klock II <pnkfelix@pnkfx.org> | 2022-01-20 14:07:54 -0500 |
|---|---|---|
| committer | Felix S. Klock II <pnkfelix@pnkfx.org> | 2022-03-03 18:58:37 -0500 |
| commit | d37da1e332a77a4cd66c2f36b4a5457f40a7bfd5 (patch) | |
| tree | f3638bd95437411b3a0c926e0ce9a864997542e9 /compiler/rustc_resolve | |
| parent | b82795244e31ce1ad60bbb823c4e4b91f921c296 (diff) | |
| download | rust-d37da1e332a77a4cd66c2f36b4a5457f40a7bfd5.tar.gz rust-d37da1e332a77a4cd66c2f36b4a5457f40a7bfd5.zip | |
Adjusted diagnostic output so that if there is no `use` in a item sequence,
then we just suggest the first legal position where you could inject a use. To do this, I added `inject_use_span` field to `ModSpans`, and populate it in parser (it is the span of the first token found after inner attributes, if any). Then I rewrote the use-suggestion code to utilize it, and threw out some stuff that is now unnecessary with this in place. (I think the result is easier to understand.) Then I added a test of issue 87613.
Diffstat (limited to 'compiler/rustc_resolve')
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 101 |
1 files changed, 48 insertions, 53 deletions
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9eedd9839eb..03b4f0609bf 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -71,7 +71,6 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; -use std::ops::ControlFlow; use std::{cmp, fmt, iter, mem, ptr}; use tracing::debug; @@ -315,74 +314,70 @@ impl<'a> From<&'a ast::PathSegment> for Segment { } } +#[derive(Debug)] struct UsePlacementFinder { target_module: NodeId, - span: Option<Span>, - found_use: bool, + first_legal_span: Option<Span>, + first_use_span: Option<Span>, } impl UsePlacementFinder { fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) { - let mut finder = UsePlacementFinder { target_module, span: None, found_use: false }; - if let ControlFlow::Continue(..) = finder.check_mod(&krate.items, CRATE_NODE_ID) { - visit::walk_crate(&mut finder, krate); - } - (finder.span, finder.found_use) - } - - fn check_mod(&mut self, items: &[P<ast::Item>], node_id: NodeId) -> ControlFlow<()> { - if self.span.is_some() { - return ControlFlow::Break(()); - } - if node_id != self.target_module { - return ControlFlow::Continue(()); - } - // find a use statement - for item in items { - match item.kind { - ItemKind::Use(..) => { - // don't suggest placing a use before the prelude - // import or other generated ones - if !item.span.from_expansion() { - self.span = Some(item.span.shrink_to_lo()); - self.found_use = true; - return ControlFlow::Break(()); - } - } - // don't place use before extern crate - ItemKind::ExternCrate(_) => {} - // but place them before the first other item - _ => { - if self.span.map_or(true, |span| item.span < span) - && !item.span.from_expansion() - { - self.span = Some(item.span.shrink_to_lo()); - // don't insert between attributes and an item - // find the first attribute on the item - // FIXME: This is broken for active attributes. - for attr in &item.attrs { - if !attr.span.is_dummy() - && self.span.map_or(true, |span| attr.span < span) - { - self.span = Some(attr.span.shrink_to_lo()); - } - } - } - } + let mut finder = + UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None }; + finder.visit_crate(krate); + if let Some(use_span) = finder.first_use_span { + (Some(use_span), true) + } else { + (finder.first_legal_span, false) + } + } +} + +fn is_span_suitable_for_use_injection(s: Span) -> bool { + // don't suggest placing a use before the prelude + // import or other generated ones + !s.from_expansion() +} + +fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> { + for item in items { + if let ItemKind::Use(..) = item.kind { + if is_span_suitable_for_use_injection(item.span) { + return Some(item.span.shrink_to_lo()); } } - ControlFlow::Continue(()) } + return None; } impl<'tcx> Visitor<'tcx> for UsePlacementFinder { + fn visit_crate(&mut self, c: &Crate) { + if self.target_module == CRATE_NODE_ID { + let inject = c.spans.inject_use_span; + if is_span_suitable_for_use_injection(inject) { + self.first_legal_span = Some(inject); + } + self.first_use_span = search_for_any_use_in_items(&c.items); + return; + } else { + visit::walk_crate(self, c); + } + } + fn visit_item(&mut self, item: &'tcx ast::Item) { - if let ItemKind::Mod(_, ModKind::Loaded(items, ..)) = &item.kind { - if let ControlFlow::Break(..) = self.check_mod(items, item.id) { + if self.target_module == item.id { + if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind { + let inject = mod_spans.inject_use_span; + if is_span_suitable_for_use_injection(inject) { + self.first_legal_span = Some(inject); + } + self.first_use_span = search_for_any_use_in_items(items); return; } + } else { + visit::walk_item(self, item); } - visit::walk_item(self, item); } } |
