found_use: bool,
}
+impl UsePlacementFinder {
+ fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
+ let mut finder = UsePlacementFinder {
+ target_module,
+ span: None,
+ found_use: false,
+ };
+ visit::walk_crate(&mut finder, krate);
+ (finder.span, finder.found_use)
+ }
+}
+
impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
fn visit_mod(
&mut self,
fn report_with_use_injections(&mut self, krate: &Crate) {
for UseError { mut err, candidates, node_id, better } in self.use_injections.drain(..) {
- let mut finder = UsePlacementFinder {
- target_module: node_id,
- span: None,
- found_use: false,
- };
- visit::walk_crate(&mut finder, krate);
+ let (span, found_use) = UsePlacementFinder::check(krate, node_id);
if !candidates.is_empty() {
- show_candidates(&mut err, finder.span, &candidates, better, finder.found_use);
+ show_candidates(&mut err, span, &candidates, better, found_use);
}
err.emit();
}
err: &mut DiagnosticBuilder,
mut msg: String,
candidates: Vec<DefId>) {
- let limit = if candidates.len() == 5 { 5 } else { 4 };
- for (i, trait_did) in candidates.iter().take(limit).enumerate() {
- msg.push_str(&format!("\ncandidate #{}: `use {};`",
- i + 1,
- self.tcx.item_path_str(*trait_did)));
- }
- if candidates.len() > limit {
- msg.push_str(&format!("\nand {} others", candidates.len() - limit));
+ let module_did = self.tcx.hir.get_module_parent(self.body_id);
+ let module_id = self.tcx.hir.as_local_node_id(module_did).unwrap();
+ let krate = self.tcx.hir.krate();
+ let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
+ if let Some(span) = span {
+ let path_strings = candidates.iter().map(|did| {
+ // produce an additional newline to separate the new use statement
+ // from the directly following item.
+ let additional_newline = if found_use {
+ ""
+ } else {
+ "\n"
+ };
+ format!("use {};\n{}", self.tcx.item_path_str(*did), additional_newline)
+ }).collect();
+
+ err.span_suggestions(span, &msg, path_strings);
+ } else {
+ let limit = if candidates.len() == 5 { 5 } else { 4 };
+ for (i, trait_did) in candidates.iter().take(limit).enumerate() {
+ msg.push_str(&format!("\ncandidate #{}: `use {};`",
+ i + 1,
+ self.tcx.item_path_str(*trait_did)));
+ }
+ if candidates.len() > limit {
+ msg.push_str(&format!("\nand {} others", candidates.len() - limit));
+ }
+ err.note(&msg[..]);
}
- err.note(&msg[..]);
}
fn suggest_valid_traits(&self,
})
}
}
+
+
+struct UsePlacementFinder<'a, 'tcx: 'a, 'gcx: 'tcx> {
+ target_module: ast::NodeId,
+ span: Option<Span>,
+ found_use: bool,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>
+}
+
+impl<'a, 'tcx, 'gcx> UsePlacementFinder<'a, 'tcx, 'gcx> {
+ fn check(
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ krate: &'tcx hir::Crate,
+ target_module: ast::NodeId,
+ ) -> (Option<Span>, bool) {
+ let mut finder = UsePlacementFinder {
+ target_module,
+ span: None,
+ found_use: false,
+ tcx,
+ };
+ hir::intravisit::walk_crate(&mut finder, krate);
+ (finder.span, finder.found_use)
+ }
+}
+
+impl<'a, 'tcx, 'gcx> hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'a, 'tcx, 'gcx> {
+ fn visit_mod(
+ &mut self,
+ module: &'tcx hir::Mod,
+ _: Span,
+ node_id: ast::NodeId,
+ ) {
+ if self.span.is_some() {
+ return;
+ }
+ if node_id != self.target_module {
+ hir::intravisit::walk_mod(self, module, node_id);
+ return;
+ }
+ // find a use statement
+ for item_id in &module.item_ids {
+ let item = self.tcx.hir.expect_item(item_id.id);
+ match item.node {
+ hir::ItemUse(..) => {
+ // don't suggest placing a use before the prelude
+ // import or other generated ones
+ if item.span.ctxt().outer().expn_info().is_none() {
+ self.span = Some(item.span.with_hi(item.span.lo()));
+ self.found_use = true;
+ return;
+ }
+ },
+ // don't place use before extern crate
+ hir::ItemExternCrate(_) => {}
+ // but place them before the first other item
+ _ => if self.span.map_or(true, |span| item.span < span ) {
+ if item.span.ctxt().outer().expn_info().is_none() {
+ // don't insert between attributes and an item
+ if item.attrs.is_empty() {
+ self.span = Some(item.span.with_hi(item.span.lo()));
+ } else {
+ // find the first attribute on the item
+ for attr in &item.attrs {
+ if self.span.map_or(true, |span| attr.span < span) {
+ self.span = Some(attr.span.with_hi(attr.span.lo()));
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ fn nested_visit_map<'this>(
+ &'this mut self
+ ) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
+ hir::intravisit::NestedVisitorMap::None
+ }
+}
| ^^^^^^
|
= help: items from traits can only be used if the trait is in scope
- = note: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
- candidate #1: `use foo::Bar;`
- candidate #2: `use no_method_suggested_traits::foo::PubPub;`
- candidate #3: `use no_method_suggested_traits::qux::PrivPub;`
- candidate #4: `use no_method_suggested_traits::Reexported;`
+help: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
+ |
+14 | use foo::Bar;
+ |
+14 | use no_method_suggested_traits::foo::PubPub;
+ |
+14 | use no_method_suggested_traits::qux::PrivPub;
+ |
+14 | use no_method_suggested_traits::Reexported;
+ |
error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&u32>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:38:44
| ^^^^^^
|
= help: items from traits can only be used if the trait is in scope
- = note: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
- candidate #1: `use foo::Bar;`
- candidate #2: `use no_method_suggested_traits::foo::PubPub;`
- candidate #3: `use no_method_suggested_traits::qux::PrivPub;`
- candidate #4: `use no_method_suggested_traits::Reexported;`
+help: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
+ |
+14 | use foo::Bar;
+ |
+14 | use no_method_suggested_traits::foo::PubPub;
+ |
+14 | use no_method_suggested_traits::qux::PrivPub;
+ |
+14 | use no_method_suggested_traits::Reexported;
+ |
error[E0599]: no method named `method` found for type `char` in the current scope
--> $DIR/no-method-suggested-traits.rs:44:9
| ^^^^^^
|
= help: items from traits can only be used if the trait is in scope
- = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
- candidate #1: `use foo::Bar;`
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+ |
+14 | use foo::Bar;
+ |
error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:48:43
| ^^^^^^
|
= help: items from traits can only be used if the trait is in scope
- = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
- candidate #1: `use foo::Bar;`
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+ |
+14 | use foo::Bar;
+ |
error[E0599]: no method named `method` found for type `i32` in the current scope
--> $DIR/no-method-suggested-traits.rs:53:10
| ^^^^^^
|
= help: items from traits can only be used if the trait is in scope
- = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
- candidate #1: `use no_method_suggested_traits::foo::PubPub;`
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+ |
+14 | use no_method_suggested_traits::foo::PubPub;
+ |
error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&i32>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:57:44
| ^^^^^^
|
= help: items from traits can only be used if the trait is in scope
- = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
- candidate #1: `use no_method_suggested_traits::foo::PubPub;`
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+ |
+14 | use no_method_suggested_traits::foo::PubPub;
+ |
error[E0599]: no method named `method` found for type `Foo` in the current scope
--> $DIR/no-method-suggested-traits.rs:62:9
24 | arg.wait();
| ^^^^
|
- = note: another candidate was found in the following trait, perhaps add a `use` for it:
- candidate #1: `use private::Future;`
+help: another candidate was found in the following trait, perhaps add a `use` for it:
+ |
+11 | use private::Future;
+ |
error: aborting due to previous error
| ^^^^^^
|
= help: items from traits can only be used if the trait is in scope
- = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
- candidate #1: `use inner::Bar;`
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+ |
+11 | use inner::Bar;
+ |
error: aborting due to previous error