]> git.lizzy.rs Git - rust.git/blob - src/librustc_resolve/error_reporting.rs
Allow a dirty MirBuilt for make_extern and make_method_extern
[rust.git] / src / librustc_resolve / error_reporting.rs
1 use crate::{CrateLint, PathResult, Segment};
2 use crate::macros::ParentScope;
3 use crate::resolve_imports::ImportResolver;
4
5 use syntax::symbol::keywords;
6 use syntax_pos::Span;
7
8 use log::debug;
9
10 use std::cmp::Reverse;
11
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(
15         &mut self,
16         span: Span,
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);
21
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()));
32             }
33             _ => return None,
34         }
35
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))
40     }
41
42     /// Suggest a missing `self::` if that resolves to an correct module.
43     ///
44     /// ```
45     ///    |
46     /// LL | use foo::Bar;
47     ///    |     ^^^ did you mean `self::foo`?
48     /// ```
49     fn make_missing_self_suggestion(
50         &mut self,
51         span: Span,
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 {
60             Some((path, None))
61         } else {
62             None
63         }
64     }
65
66     /// Suggest a missing `crate::` if that resolves to an correct module.
67     ///
68     /// ```
69     ///    |
70     /// LL | use foo::Bar;
71     ///    |     ^^^ did you mean `crate::foo`?
72     /// ```
73     fn make_missing_crate_suggestion(
74         &mut self,
75         span: Span,
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 {
84             Some((
85                 path,
86                 Some(
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()
90                 ),
91             ))
92         } else {
93             None
94         }
95     }
96
97     /// Suggest a missing `super::` if that resolves to an correct module.
98     ///
99     /// ```
100     ///    |
101     /// LL | use foo::Bar;
102     ///    |     ^^^ did you mean `super::foo`?
103     /// ```
104     fn make_missing_super_suggestion(
105         &mut self,
106         span: Span,
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 {
115             Some((path, None))
116         } else {
117             None
118         }
119     }
120
121     /// Suggest a missing external crate name if that resolves to an correct module.
122     ///
123     /// ```
124     ///    |
125     /// LL | use foobar::Baz;
126     ///    |     ^^^^^^ did you mean `baz::foobar`?
127     /// ```
128     ///
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(
132         &mut self,
133         span: Span,
134         mut path: Vec<Segment>,
135         parent_scope: &ParentScope<'b>,
136     ) -> Option<(Vec<Segment>, Option<String>)> {
137         if path[1].ident.span.rust_2015() {
138             return None;
139         }
140
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()));
147
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={:?}",
153                     name, path, result);
154             if let PathResult::Module(..) = result {
155                 return Some((path, None));
156             }
157         }
158
159         None
160     }
161 }