]> git.lizzy.rs Git - rust.git/blob - src/librustc_resolve/error_reporting.rs
rustbuild: fix remap-debuginfo when building a release
[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};
12
13 use std::collections::BTreeSet;
14
15 use syntax::ast::Ident;
16 use syntax::symbol::{keywords, Symbol};
17 use syntax_pos::Span;
18
19 use resolve_imports::ImportResolver;
20
21 impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
22     /// Add suggestions for a path that cannot be resolved.
23     pub(crate) fn make_path_suggestion(
24         &mut self,
25         span: Span,
26         path: Vec<Ident>
27     ) -> Option<Vec<Ident>> {
28         debug!("make_path_suggestion: span={:?} path={:?}", span, path);
29         // If we don't have a path to suggest changes to, then return.
30         if path.is_empty() {
31             return None;
32         }
33
34         // Check whether a ident is a path segment that is not root.
35         let is_special = |ident: Ident| ident.is_path_segment_keyword() &&
36                                         ident.name != keywords::CrateRoot.name();
37
38         match (path.get(0), path.get(1)) {
39             // Make suggestions that require at least two non-special path segments.
40             (Some(fst), Some(snd)) if !is_special(*fst) && !is_special(*snd) => {
41                 debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd);
42
43                 self.make_missing_self_suggestion(span, path.clone())
44                     .or_else(|| self.make_missing_crate_suggestion(span, path.clone()))
45                     .or_else(|| self.make_missing_super_suggestion(span, path.clone()))
46                     .or_else(|| self.make_external_crate_suggestion(span, path.clone()))
47             },
48             _ => None,
49         }
50     }
51
52     /// Suggest a missing `self::` if that resolves to an correct module.
53     ///
54     /// ```
55     ///    |
56     /// LL | use foo::Bar;
57     ///    |     ^^^ Did you mean `self::foo`?
58     /// ```
59     fn make_missing_self_suggestion(
60         &mut self,
61         span: Span,
62         mut path: Vec<Ident>
63     ) -> Option<Vec<Ident>> {
64         // Replace first ident with `self` and check if that is valid.
65         path[0].name = keywords::SelfValue.name();
66         let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
67         debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
68         if let PathResult::Module(..) = result {
69             Some(path)
70         } else {
71             None
72         }
73     }
74
75     /// Suggest a missing `crate::` if that resolves to an correct module.
76     ///
77     /// ```
78     ///    |
79     /// LL | use foo::Bar;
80     ///    |     ^^^ Did you mean `crate::foo`?
81     /// ```
82     fn make_missing_crate_suggestion(
83         &mut self,
84         span: Span,
85         mut path: Vec<Ident>
86     ) -> Option<Vec<Ident>> {
87         // Replace first ident with `crate` and check if that is valid.
88         path[0].name = keywords::Crate.name();
89         let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
90         debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
91         if let PathResult::Module(..) = result {
92             Some(path)
93         } else {
94             None
95         }
96     }
97
98     /// Suggest a missing `super::` if that resolves to an correct module.
99     ///
100     /// ```
101     ///    |
102     /// LL | use foo::Bar;
103     ///    |     ^^^ Did you mean `super::foo`?
104     /// ```
105     fn make_missing_super_suggestion(
106         &mut self,
107         span: Span,
108         mut path: Vec<Ident>
109     ) -> Option<Vec<Ident>> {
110         // Replace first ident with `crate` and check if that is valid.
111         path[0].name = keywords::Super.name();
112         let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
113         debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
114         if let PathResult::Module(..) = result {
115             Some(path)
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<Ident>
135     ) -> Option<Vec<Ident>> {
136         // Need to clone else we can't call `resolve_path` without a borrow error. We also store
137         // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
138         // each time.
139         let external_crate_names: BTreeSet<Symbol> = self.resolver.extern_prelude
140             .clone().drain().collect();
141
142         // Insert a new path segment that we can replace.
143         let new_path_segment = path[0].clone();
144         path.insert(1, new_path_segment);
145
146         // Iterate in reverse so that we start with crates at the end of the alphabet. This means
147         // that we'll always get `std` before `core`.
148         for name in external_crate_names.iter().rev() {
149             let ident = Ident::with_empty_ctxt(*name);
150             // Calling `maybe_process_path_extern` ensures that we're only running `resolve_path`
151             // on a crate name that won't ICE.
152             if let Some(_) = self.crate_loader.maybe_process_path_extern(*name, ident.span) {
153                 // Replace the first after root (a placeholder we inserted) with a crate name
154                 // and check if that is valid.
155                 path[1].name = *name;
156                 let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
157                 debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
158                        name, path, result);
159                 if let PathResult::Module(..) = result {
160                     return Some(path)
161                 }
162             }
163         }
164
165         // Remove our placeholder segment.
166         path.remove(1);
167         None
168     }
169 }