]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/unqualified_path.rs
Merge #10649
[rust.git] / crates / ide_completion / src / completions / unqualified_path.rs
1 //! Completion of names from the current scope, e.g. locals and imported items.
2
3 use hir::ScopeDef;
4 use syntax::{ast, AstNode};
5
6 use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
7
8 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
9     if ctx.is_path_disallowed() || !ctx.is_trivial_path() || ctx.has_impl_or_trait_prev_sibling() {
10         return;
11     }
12
13     if ctx.in_use_tree() {
14         // only show modules in a fresh UseTree
15         cov_mark::hit!(unqualified_path_only_modules_in_import);
16         ctx.process_all_names(&mut |name, res| {
17             if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
18                 acc.add_resolution(ctx, name, &res);
19             }
20         });
21
22         ["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
23         return;
24     }
25     ["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
26
27     match &ctx.completion_location {
28         Some(ImmediateLocation::Visibility(_)) => return,
29         Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
30             // only show macros in {Assoc}ItemList
31             ctx.process_all_names(&mut |name, res| {
32                 if let hir::ScopeDef::MacroDef(mac) = res {
33                     if mac.is_fn_like() {
34                         acc.add_macro(ctx, Some(name.clone()), mac);
35                     }
36                 }
37                 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
38                     acc.add_resolution(ctx, name, &res);
39                 }
40             });
41             return;
42         }
43         Some(ImmediateLocation::TypeBound) => {
44             ctx.process_all_names(&mut |name, res| {
45                 let add_resolution = match res {
46                     ScopeDef::MacroDef(mac) => mac.is_fn_like(),
47                     ScopeDef::ModuleDef(hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_)) => {
48                         true
49                     }
50                     _ => false,
51                 };
52                 if add_resolution {
53                     acc.add_resolution(ctx, name, &res);
54                 }
55             });
56             return;
57         }
58         _ => (),
59     }
60
61     if !ctx.expects_type() {
62         if let Some(hir::Adt::Enum(e)) =
63             ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
64         {
65             super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| {
66                 acc.add_qualified_enum_variant(ctx, variant, path)
67             });
68         }
69     }
70
71     if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location {
72         if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) {
73             if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) =
74                 ctx.sema.resolve_path(&path_seg.parent_path())
75             {
76                 trait_.items(ctx.sema.db).into_iter().for_each(|it| {
77                     if let hir::AssocItem::TypeAlias(alias) = it {
78                         acc.add_type_alias_with_eq(ctx, alias)
79                     }
80                 });
81             }
82         }
83     }
84
85     ctx.process_all_names(&mut |name, res| {
86         let add_resolution = match res {
87             ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => {
88                 cov_mark::hit!(unqualified_skip_lifetime_completion);
89                 return;
90             }
91             ScopeDef::ImplSelfType(_) => {
92                 !ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for])
93             }
94             // Don't suggest attribute macros and derives.
95             ScopeDef::MacroDef(mac) => mac.is_fn_like(),
96             // no values in type places
97             ScopeDef::ModuleDef(
98                 hir::ModuleDef::Function(_)
99                 | hir::ModuleDef::Variant(_)
100                 | hir::ModuleDef::Static(_),
101             )
102             | ScopeDef::Local(_) => !ctx.expects_type(),
103             // unless its a constant in a generic arg list position
104             ScopeDef::ModuleDef(hir::ModuleDef::Const(_))
105             | ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => {
106                 !ctx.expects_type() || ctx.expects_generic_arg()
107             }
108             _ => true,
109         };
110         if add_resolution {
111             acc.add_resolution(ctx, name, &res);
112         }
113     });
114 }
115
116 #[cfg(test)]
117 mod tests {
118     use expect_test::{expect, Expect};
119
120     use crate::tests::{check_edit, completion_list_no_kw};
121
122     fn check(ra_fixture: &str, expect: Expect) {
123         let actual = completion_list_no_kw(ra_fixture);
124         expect.assert_eq(&actual)
125     }
126
127     #[test]
128     fn completes_if_prefix_is_keyword() {
129         check_edit(
130             "wherewolf",
131             r#"
132 fn main() {
133     let wherewolf = 92;
134     drop(where$0)
135 }
136 "#,
137             r#"
138 fn main() {
139     let wherewolf = 92;
140     drop(wherewolf)
141 }
142 "#,
143         )
144     }
145
146     /// Regression test for issue #6091.
147     #[test]
148     fn correctly_completes_module_items_prefixed_with_underscore() {
149         check_edit(
150             "_alpha",
151             r#"
152 fn main() {
153     _$0
154 }
155 fn _alpha() {}
156 "#,
157             r#"
158 fn main() {
159     _alpha()$0
160 }
161 fn _alpha() {}
162 "#,
163         )
164     }
165
166     #[test]
167     fn completes_prelude() {
168         check(
169             r#"
170 //- /main.rs crate:main deps:std
171 fn foo() { let x: $0 }
172
173 //- /std/lib.rs crate:std
174 pub mod prelude {
175     pub mod rust_2018 {
176         pub struct Option;
177     }
178 }
179 "#,
180             expect![[r#"
181                 md std
182                 bt u32
183                 st Option
184             "#]],
185         );
186     }
187
188     #[test]
189     fn completes_prelude_macros() {
190         check(
191             r#"
192 //- /main.rs crate:main deps:std
193 fn f() {$0}
194
195 //- /std/lib.rs crate:std
196 pub mod prelude {
197     pub mod rust_2018 {
198         pub use crate::concat;
199     }
200 }
201
202 mod macros {
203     #[rustc_builtin_macro]
204     #[macro_export]
205     macro_rules! concat { }
206 }
207 "#,
208             expect![[r##"
209                 fn f()        fn()
210                 ma concat!(…) #[macro_export] macro_rules! concat
211                 md std
212                 bt u32
213             "##]],
214         );
215     }
216
217     #[test]
218     fn completes_std_prelude_if_core_is_defined() {
219         check(
220             r#"
221 //- /main.rs crate:main deps:core,std
222 fn foo() { let x: $0 }
223
224 //- /core/lib.rs crate:core
225 pub mod prelude {
226     pub mod rust_2018 {
227         pub struct Option;
228     }
229 }
230
231 //- /std/lib.rs crate:std deps:core
232 pub mod prelude {
233     pub mod rust_2018 {
234         pub struct String;
235     }
236 }
237 "#,
238             expect![[r#"
239                 md std
240                 md core
241                 bt u32
242                 st String
243             "#]],
244         );
245     }
246
247     #[test]
248     fn respects_doc_hidden() {
249         check(
250             r#"
251 //- /lib.rs crate:lib deps:std
252 fn f() {
253     format_$0
254 }
255
256 //- /std.rs crate:std
257 #[doc(hidden)]
258 #[macro_export]
259 macro_rules! format_args_nl {
260     () => {}
261 }
262
263 pub mod prelude {
264     pub mod rust_2018 {}
265 }
266             "#,
267             expect![[r#"
268                 fn f() fn()
269                 md std
270                 bt u32
271             "#]],
272         );
273     }
274
275     #[test]
276     fn respects_doc_hidden_in_assoc_item_list() {
277         check(
278             r#"
279 //- /lib.rs crate:lib deps:std
280 struct S;
281 impl S {
282     format_$0
283 }
284
285 //- /std.rs crate:std
286 #[doc(hidden)]
287 #[macro_export]
288 macro_rules! format_args_nl {
289     () => {}
290 }
291
292 pub mod prelude {
293     pub mod rust_2018 {}
294 }
295             "#,
296             expect![[r#"
297                 md std
298             "#]],
299         );
300     }
301 }