1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use {CrateLint, PathResult, Segment};
12 use macros::ParentScope;
14 use syntax::symbol::keywords;
17 use resolve_imports::ImportResolver;
18 use std::cmp::Reverse;
20 impl<'a, 'b:'a> ImportResolver<'a, 'b> {
21 /// Add suggestions for a path that cannot be resolved.
22 pub(crate) fn make_path_suggestion(
25 mut path: Vec<Segment>,
26 parent_scope: &ParentScope<'b>,
27 ) -> Option<(Vec<Segment>, Option<String>)> {
28 debug!("make_path_suggestion: span={:?} path={:?}", span, path);
30 match (path.get(0), path.get(1)) {
31 // `{{root}}::ident::...` on both editions.
32 // On 2015 `{{root}}` is usually added implicitly.
33 (Some(fst), Some(snd)) if fst.ident.name == keywords::PathRoot.name() &&
34 !snd.ident.is_path_segment_keyword() => {}
35 // `ident::...` on 2018
36 (Some(fst), _) if fst.ident.span.rust_2018() &&
37 !fst.ident.is_path_segment_keyword() => {
38 // Insert a placeholder that's later replaced by `self`/`super`/etc.
39 path.insert(0, Segment::from_ident(keywords::Invalid.ident()));
44 self.make_missing_self_suggestion(span, path.clone(), parent_scope)
45 .or_else(|| self.make_missing_crate_suggestion(span, path.clone(), parent_scope))
46 .or_else(|| self.make_missing_super_suggestion(span, path.clone(), parent_scope))
47 .or_else(|| self.make_external_crate_suggestion(span, path, parent_scope))
50 /// Suggest a missing `self::` if that resolves to an correct module.
54 /// LL | use foo::Bar;
55 /// | ^^^ did you mean `self::foo`?
57 fn make_missing_self_suggestion(
60 mut path: Vec<Segment>,
61 parent_scope: &ParentScope<'b>,
62 ) -> Option<(Vec<Segment>, Option<String>)> {
63 // Replace first ident with `self` and check if that is valid.
64 path[0].ident.name = keywords::SelfLower.name();
65 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
66 debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
67 if let PathResult::Module(..) = result {
74 /// Suggest a missing `crate::` if that resolves to an correct module.
78 /// LL | use foo::Bar;
79 /// | ^^^ did you mean `crate::foo`?
81 fn make_missing_crate_suggestion(
84 mut path: Vec<Segment>,
85 parent_scope: &ParentScope<'b>,
86 ) -> Option<(Vec<Segment>, Option<String>)> {
87 // Replace first ident with `crate` and check if that is valid.
88 path[0].ident.name = keywords::Crate.name();
89 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
90 debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
91 if let PathResult::Module(..) = result {
95 "`use` statements changed in Rust 2018; read more at \
96 <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
97 clarity.html>".to_string()
105 /// Suggest a missing `super::` if that resolves to an correct module.
109 /// LL | use foo::Bar;
110 /// | ^^^ did you mean `super::foo`?
112 fn make_missing_super_suggestion(
115 mut path: Vec<Segment>,
116 parent_scope: &ParentScope<'b>,
117 ) -> Option<(Vec<Segment>, Option<String>)> {
118 // Replace first ident with `crate` and check if that is valid.
119 path[0].ident.name = keywords::Super.name();
120 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
121 debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
122 if let PathResult::Module(..) = result {
129 /// Suggest a missing external crate name if that resolves to an correct module.
133 /// LL | use foobar::Baz;
134 /// | ^^^^^^ did you mean `baz::foobar`?
137 /// Used when importing a submodule of an external crate but missing that crate's
138 /// name as the first part of path.
139 fn make_external_crate_suggestion(
142 mut path: Vec<Segment>,
143 parent_scope: &ParentScope<'b>,
144 ) -> Option<(Vec<Segment>, Option<String>)> {
145 if path[1].ident.span.rust_2015() {
149 // Sort extern crate names in reverse order to get
150 // 1) some consistent ordering for emitted dignostics and
151 // 2) `std` suggestions before `core` suggestions.
152 let mut extern_crate_names =
153 self.resolver.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
154 extern_crate_names.sort_by_key(|name| Reverse(name.as_str()));
156 for name in extern_crate_names.into_iter() {
157 // Replace first ident with a crate name and check if that is valid.
158 path[0].ident.name = name;
159 let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
160 debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
162 if let PathResult::Module(..) = result {
163 return Some((path, None));