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};
13 use std::collections::BTreeSet;
15 use syntax::ast::Ident;
16 use syntax::symbol::{keywords, Symbol};
19 use resolve_imports::ImportResolver;
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(
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.
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();
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);
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()))
52 /// Suggest a missing `self::` if that resolves to an correct module.
56 /// LL | use foo::Bar;
57 /// | ^^^ Did you mean `self::foo`?
59 fn make_missing_self_suggestion(
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 {
75 /// Suggest a missing `crate::` if that resolves to an correct module.
79 /// LL | use foo::Bar;
80 /// | ^^^ Did you mean `crate::foo`?
82 fn make_missing_crate_suggestion(
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 {
98 /// Suggest a missing `super::` if that resolves to an correct module.
102 /// LL | use foo::Bar;
103 /// | ^^^ Did you mean `super::foo`?
105 fn make_missing_super_suggestion(
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 {
121 /// Suggest a missing external crate name if that resolves to an correct module.
125 /// LL | use foobar::Baz;
126 /// | ^^^^^^ Did you mean `baz::foobar`?
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(
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)
139 let external_crate_names: BTreeSet<Symbol> = self.resolver.extern_prelude
140 .clone().drain().collect();
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);
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={:?}",
159 if let PathResult::Module(..) = result {
165 // Remove our placeholder segment.