]> git.lizzy.rs Git - rust.git/blob - src/librustc_resolve/error_reporting.rs
Rollup merge of #55470 - daniellimws:box-from-docs, r=Centril
[rust.git] / src / librustc_resolve / error_reporting.rs
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.
4 //
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.
10
11 use {CrateLint, PathResult, Segment};
12 use macros::ParentScope;
13
14 use syntax::symbol::keywords;
15 use syntax_pos::Span;
16
17 use resolve_imports::ImportResolver;
18 use std::cmp::Reverse;
19
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(
23         &mut self,
24         span: Span,
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);
29
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()));
40             }
41             _ => return None,
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))
48     }
49
50     /// Suggest a missing `self::` if that resolves to an correct module.
51     ///
52     /// ```
53     ///    |
54     /// LL | use foo::Bar;
55     ///    |     ^^^ did you mean `self::foo`?
56     /// ```
57     fn make_missing_self_suggestion(
58         &mut self,
59         span: Span,
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 {
68             Some((path, None))
69         } else {
70             None
71         }
72     }
73
74     /// Suggest a missing `crate::` if that resolves to an correct module.
75     ///
76     /// ```
77     ///    |
78     /// LL | use foo::Bar;
79     ///    |     ^^^ did you mean `crate::foo`?
80     /// ```
81     fn make_missing_crate_suggestion(
82         &mut self,
83         span: Span,
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 {
92             Some((
93                 path,
94                 Some(
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()
98                 ),
99             ))
100         } else {
101             None
102         }
103     }
104
105     /// Suggest a missing `super::` if that resolves to an correct module.
106     ///
107     /// ```
108     ///    |
109     /// LL | use foo::Bar;
110     ///    |     ^^^ did you mean `super::foo`?
111     /// ```
112     fn make_missing_super_suggestion(
113         &mut self,
114         span: Span,
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 {
123             Some((path, None))
124         } else {
125             None
126         }
127     }
128
129     /// Suggest a missing external crate name if that resolves to an correct module.
130     ///
131     /// ```
132     ///    |
133     /// LL | use foobar::Baz;
134     ///    |     ^^^^^^ did you mean `baz::foobar`?
135     /// ```
136     ///
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(
140         &mut self,
141         span: Span,
142         mut path: Vec<Segment>,
143         parent_scope: &ParentScope<'b>,
144     ) -> Option<(Vec<Segment>, Option<String>)> {
145         if path[1].ident.span.rust_2015() {
146             return None;
147         }
148
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()));
155
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={:?}",
161                     name, path, result);
162             if let PathResult::Module(..) = result {
163                 return Some((path, None));
164             }
165         }
166
167         None
168     }
169 }