1 use crate::{CrateLint, PathResult, Segment};
2 use crate::macros::ParentScope;
3 use crate::resolve_imports::ImportResolver;
5 use syntax::symbol::keywords;
10 use std::cmp::Reverse;
12 impl<'a, 'b:'a> ImportResolver<'a, 'b> {
13 /// Add suggestions for a path that cannot be resolved.
14 pub(crate) fn make_path_suggestion(
17 mut path: Vec<Segment>,
18 parent_scope: &ParentScope<'b>,
19 ) -> Option<(Vec<Segment>, Option<String>)> {
20 debug!("make_path_suggestion: span={:?} path={:?}", span, path);
22 match (path.get(0), path.get(1)) {
23 // `{{root}}::ident::...` on both editions.
24 // On 2015 `{{root}}` is usually added implicitly.
25 (Some(fst), Some(snd)) if fst.ident.name == keywords::PathRoot.name() &&
26 !snd.ident.is_path_segment_keyword() => {}
27 // `ident::...` on 2018
28 (Some(fst), _) if fst.ident.span.rust_2018() &&
29 !fst.ident.is_path_segment_keyword() => {
30 // Insert a placeholder that's later replaced by `self`/`super`/etc.
31 path.insert(0, Segment::from_ident(keywords::Invalid.ident()));
36 self.make_missing_self_suggestion(span, path.clone(), parent_scope)
37 .or_else(|| self.make_missing_crate_suggestion(span, path.clone(), parent_scope))
38 .or_else(|| self.make_missing_super_suggestion(span, path.clone(), parent_scope))
39 .or_else(|| self.make_external_crate_suggestion(span, path, parent_scope))
42 /// Suggest a missing `self::` if that resolves to an correct module.
46 /// LL | use foo::Bar;
47 /// | ^^^ did you mean `self::foo`?
49 fn make_missing_self_suggestion(
52 mut path: Vec<Segment>,
53 parent_scope: &ParentScope<'b>,
54 ) -> Option<(Vec<Segment>, Option<String>)> {
55 // Replace first ident with `self` and check if that is valid.
56 path[0].ident.name = keywords::SelfLower.name();
57 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
58 debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
59 if let PathResult::Module(..) = result {
66 /// Suggest a missing `crate::` if that resolves to an correct module.
70 /// LL | use foo::Bar;
71 /// | ^^^ did you mean `crate::foo`?
73 fn make_missing_crate_suggestion(
76 mut path: Vec<Segment>,
77 parent_scope: &ParentScope<'b>,
78 ) -> Option<(Vec<Segment>, Option<String>)> {
79 // Replace first ident with `crate` and check if that is valid.
80 path[0].ident.name = keywords::Crate.name();
81 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
82 debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
83 if let PathResult::Module(..) = result {
87 "`use` statements changed in Rust 2018; read more at \
88 <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
89 clarity.html>".to_string()
97 /// Suggest a missing `super::` if that resolves to an correct module.
101 /// LL | use foo::Bar;
102 /// | ^^^ did you mean `super::foo`?
104 fn make_missing_super_suggestion(
107 mut path: Vec<Segment>,
108 parent_scope: &ParentScope<'b>,
109 ) -> Option<(Vec<Segment>, Option<String>)> {
110 // Replace first ident with `crate` and check if that is valid.
111 path[0].ident.name = keywords::Super.name();
112 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
113 debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
114 if let PathResult::Module(..) = result {
121 /// Suggest a missing external crate name if that resolves to an correct module.
125 /// LL | use foobar::Baz;
126 /// | ^^^^^^ did you mean `baz::foobar`?
129 /// Used when importing a submodule of an external crate but missing that crate's
130 /// name as the first part of path.
131 fn make_external_crate_suggestion(
134 mut path: Vec<Segment>,
135 parent_scope: &ParentScope<'b>,
136 ) -> Option<(Vec<Segment>, Option<String>)> {
137 if path[1].ident.span.rust_2015() {
141 // Sort extern crate names in reverse order to get
142 // 1) some consistent ordering for emitted dignostics and
143 // 2) `std` suggestions before `core` suggestions.
144 let mut extern_crate_names =
145 self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
146 extern_crate_names.sort_by_key(|name| Reverse(name.as_str()));
148 for name in extern_crate_names.into_iter() {
149 // Replace first ident with a crate name and check if that is valid.
150 path[0].ident.name = name;
151 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
152 debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
154 if let PathResult::Module(..) = result {
155 return Some((path, None));