1111use { CrateLint , PathResult } ;
1212use macros:: ParentScope ;
1313
14- use std:: collections:: BTreeSet ;
15-
1614use syntax:: ast:: Ident ;
17- use syntax:: symbol:: { keywords, Symbol } ;
15+ use syntax:: symbol:: keywords;
1816use syntax_pos:: Span ;
1917
2018use resolve_imports:: ImportResolver ;
19+ use std:: cmp:: Reverse ;
2120
2221impl < ' a , ' b : ' a , ' c : ' b > ImportResolver < ' a , ' b , ' c > {
2322 /// Add suggestions for a path that cannot be resolved.
2423 pub ( crate ) fn make_path_suggestion (
2524 & mut self ,
2625 span : Span ,
27- path : Vec < Ident > ,
26+ mut path : Vec < Ident > ,
2827 parent_scope : & ParentScope < ' b > ,
2928 ) -> Option < ( Vec < Ident > , Option < String > ) > {
3029 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 ( ) ;
3930
4031 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) && !is_special ( * snd) => {
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 ,
5342 }
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) )
5448 }
5549
5650 /// 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> {
148142 mut path : Vec < Ident > ,
149143 parent_scope : & ParentScope < ' b > ,
150144 ) -> Option < ( Vec < Ident > , 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+ }
156148
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 ( ) ) ) ;
160155
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 ] . 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 ] . name = name;
167159 let result = self . resolve_path ( & path, None , parent_scope, false , span, CrateLint :: No ) ;
168160 debug ! ( "make_external_crate_suggestion: name={:?} path={:?} result={:?}" ,
169161 name, path, result) ;
@@ -172,8 +164,6 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
172164 }
173165 }
174166
175- // Remove our placeholder segment.
176- path. remove ( 1 ) ;
177167 None
178168 }
179169}
0 commit comments