|
11 | 11 | use {CrateLint, PathResult, Segment};
|
12 | 12 | use macros::ParentScope;
|
13 | 13 |
|
14 |
| -use std::collections::BTreeSet; |
15 |
| - |
16 | 14 | use syntax::ast::Ident;
|
17 |
| -use syntax::symbol::{keywords, Symbol}; |
| 15 | +use syntax::symbol::keywords; |
18 | 16 | use syntax_pos::Span;
|
19 | 17 |
|
20 | 18 | use resolve_imports::ImportResolver;
|
| 19 | +use std::cmp::Reverse; |
21 | 20 |
|
22 | 21 | impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
23 | 22 | /// Add suggestions for a path that cannot be resolved.
|
24 | 23 | pub(crate) fn make_path_suggestion(
|
25 | 24 | &mut self,
|
26 | 25 | span: Span,
|
27 |
| - path: Vec<Segment>, |
| 26 | + mut path: Vec<Segment>, |
28 | 27 | parent_scope: &ParentScope<'b>,
|
29 | 28 | ) -> Option<(Vec<Segment>, Option<String>)> {
|
30 | 29 | debug!("make_path_suggestion: span={:?} path={:?}", span, path);
|
31 |
| - // If we don't have a path to suggest changes to, then return. |
32 |
| - if path.is_empty() { |
33 |
| - return None; |
34 |
| - } |
35 |
| - |
36 |
| - // Check whether a ident is a path segment that is not root. |
37 |
| - let is_special = |ident: Ident| ident.is_path_segment_keyword() && |
38 |
| - ident.name != keywords::CrateRoot.name(); |
39 | 30 |
|
40 | 31 | match (path.get(0), path.get(1)) {
|
41 |
| - // Make suggestions that require at least two non-special path segments. |
42 |
| - (Some(fst), Some(snd)) if !is_special(fst.ident) && !is_special(snd.ident) => { |
43 |
| - debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd); |
44 |
| - |
45 |
| - self.make_missing_self_suggestion(span, path.clone(), parent_scope) |
46 |
| - .or_else(|| self.make_missing_crate_suggestion(span, path.clone(), |
47 |
| - parent_scope)) |
48 |
| - .or_else(|| self.make_missing_super_suggestion(span, path.clone(), |
49 |
| - parent_scope)) |
50 |
| - .or_else(|| self.make_external_crate_suggestion(span, path, parent_scope)) |
51 |
| - }, |
52 |
| - _ => None, |
| 32 | + // `{{root}}::ident::...` on both editions. |
| 33 | + // On 2015 `{{root}}` is usually added implicitly. |
| 34 | + (Some(fst), Some(snd)) if fst.name == keywords::CrateRoot.name() && |
| 35 | + !snd.is_path_segment_keyword() => {} |
| 36 | + // `ident::...` on 2018 |
| 37 | + (Some(fst), _) if self.session.rust_2018() && !fst.is_path_segment_keyword() => { |
| 38 | + // Insert a placeholder that's later replaced by `self`/`super`/etc. |
| 39 | + path.insert(0, keywords::Invalid.ident()); |
| 40 | + } |
| 41 | + _ => return None, |
53 | 42 | }
|
| 43 | + |
| 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)) |
54 | 48 | }
|
55 | 49 |
|
56 | 50 | /// Suggest a missing `self::` if that resolves to an correct module.
|
@@ -148,22 +142,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
148 | 142 | mut path: Vec<Segment>,
|
149 | 143 | parent_scope: &ParentScope<'b>,
|
150 | 144 | ) -> Option<(Vec<Segment>, Option<String>)> {
|
151 |
| - // Need to clone else we can't call `resolve_path` without a borrow error. We also store |
152 |
| - // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic) |
153 |
| - // each time. |
154 |
| - let external_crate_names: BTreeSet<Symbol> = self.resolver.extern_prelude |
155 |
| - .iter().map(|(ident, _)| ident.name).collect(); |
| 145 | + if !self.session.rust_2018() { |
| 146 | + return None; |
| 147 | + } |
156 | 148 |
|
157 |
| - // Insert a new path segment that we can replace. |
158 |
| - let new_path_segment = path[0].clone(); |
159 |
| - path.insert(1, new_path_segment); |
| 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())); |
160 | 155 |
|
161 |
| - // Iterate in reverse so that we start with crates at the end of the alphabet. This means |
162 |
| - // that we'll always get `std` before `core`. |
163 |
| - for name in external_crate_names.iter().rev() { |
164 |
| - // Replace the first after root (a placeholder we inserted) with a crate name |
165 |
| - // and check if that is valid. |
166 |
| - path[1].ident.name = *name; |
| 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; |
167 | 159 | let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No);
|
168 | 160 | debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
|
169 | 161 | name, path, result);
|
|
0 commit comments