]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
Merge commit 'b52fb5234cd7c11ecfae51897a6f7fa52e8777fc' into clippyup
[rust.git] / src / tools / rust-analyzer / crates / ide-completion / src / completions / type.rs
1 //! Completion of names from the current scope in type position.
2
3 use hir::{HirDisplay, ScopeDef};
4 use syntax::{ast, AstNode, SyntaxKind};
5
6 use crate::{
7     context::{PathCompletionCtx, Qualified, TypeAscriptionTarget, TypeLocation},
8     render::render_type_inference,
9     CompletionContext, Completions,
10 };
11
12 pub(crate) fn complete_type_path(
13     acc: &mut Completions,
14     ctx: &CompletionContext<'_>,
15     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
16     location: &TypeLocation,
17 ) {
18     let _p = profile::span("complete_type_path");
19
20     let scope_def_applicable = |def| {
21         use hir::{GenericParam::*, ModuleDef::*};
22         match def {
23             ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
24             // no values in type places
25             ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false,
26             // unless its a constant in a generic arg list position
27             ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
28                 matches!(location, TypeLocation::GenericArgList(_))
29             }
30             ScopeDef::ImplSelfType(_) => {
31                 !matches!(location, TypeLocation::ImplTarget | TypeLocation::ImplTrait)
32             }
33             // Don't suggest attribute macros and derives.
34             ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
35             // Type things are fine
36             ScopeDef::ModuleDef(BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_))
37             | ScopeDef::AdtSelfType(_)
38             | ScopeDef::Unknown
39             | ScopeDef::GenericParam(TypeParam(_)) => true,
40         }
41     };
42
43     let add_assoc_item = |acc: &mut Completions, item| match item {
44         hir::AssocItem::Const(ct) if matches!(location, TypeLocation::GenericArgList(_)) => {
45             acc.add_const(ctx, ct)
46         }
47         hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => (),
48         hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
49     };
50
51     match qualified {
52         Qualified::TypeAnchor { ty: None, trait_: None } => ctx
53             .traits_in_scope()
54             .iter()
55             .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
56             .for_each(|item| add_assoc_item(acc, item)),
57         Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
58             trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
59         }
60         Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
61             ctx.iterate_path_candidates(&ty, |item| {
62                 add_assoc_item(acc, item);
63             });
64
65             // Iterate assoc types separately
66             ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
67                 if let hir::AssocItem::TypeAlias(ty) = item {
68                     acc.add_type_alias(ctx, ty)
69                 }
70                 None::<()>
71             });
72         }
73         Qualified::With { resolution: None, .. } => {}
74         Qualified::With { resolution: Some(resolution), .. } => {
75             // Add associated types on type parameters and `Self`.
76             ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
77                 acc.add_type_alias(ctx, alias);
78                 None::<()>
79             });
80
81             match resolution {
82                 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
83                     let module_scope = module.scope(ctx.db, Some(ctx.module));
84                     for (name, def) in module_scope {
85                         if scope_def_applicable(def) {
86                             acc.add_path_resolution(ctx, path_ctx, name, def);
87                         }
88                     }
89                 }
90                 hir::PathResolution::Def(
91                     def @ (hir::ModuleDef::Adt(_)
92                     | hir::ModuleDef::TypeAlias(_)
93                     | hir::ModuleDef::BuiltinType(_)),
94                 ) => {
95                     let ty = match def {
96                         hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
97                         hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
98                         hir::ModuleDef::BuiltinType(builtin) => builtin.ty(ctx.db),
99                         _ => return,
100                     };
101
102                     // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
103                     // (where AssocType is defined on a trait, not an inherent impl)
104
105                     ctx.iterate_path_candidates(&ty, |item| {
106                         add_assoc_item(acc, item);
107                     });
108
109                     // Iterate assoc types separately
110                     ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
111                         if let hir::AssocItem::TypeAlias(ty) = item {
112                             acc.add_type_alias(ctx, ty)
113                         }
114                         None::<()>
115                     });
116                 }
117                 hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
118                     // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
119                     for item in t.items(ctx.db) {
120                         add_assoc_item(acc, item);
121                     }
122                 }
123                 hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
124                     let ty = match resolution {
125                         hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
126                         hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
127                         _ => return,
128                     };
129
130                     ctx.iterate_path_candidates(&ty, |item| {
131                         add_assoc_item(acc, item);
132                     });
133                 }
134                 _ => (),
135             }
136         }
137         Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
138         Qualified::No => {
139             match location {
140                 TypeLocation::TypeBound => {
141                     acc.add_nameref_keywords_with_colon(ctx);
142                     ctx.process_all_names(&mut |name, res| {
143                         let add_resolution = match res {
144                             ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
145                                 mac.is_fn_like(ctx.db)
146                             }
147                             ScopeDef::ModuleDef(
148                                 hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_),
149                             ) => true,
150                             _ => false,
151                         };
152                         if add_resolution {
153                             acc.add_path_resolution(ctx, path_ctx, name, res);
154                         }
155                     });
156                     return;
157                 }
158                 TypeLocation::GenericArgList(Some(arg_list)) => {
159                     let in_assoc_type_arg = ctx
160                         .original_token
161                         .parent_ancestors()
162                         .any(|node| node.kind() == SyntaxKind::ASSOC_TYPE_ARG);
163
164                     if !in_assoc_type_arg {
165                         if let Some(path_seg) =
166                             arg_list.syntax().parent().and_then(ast::PathSegment::cast)
167                         {
168                             if path_seg
169                                 .syntax()
170                                 .ancestors()
171                                 .find_map(ast::TypeBound::cast)
172                                 .is_some()
173                             {
174                                 if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(
175                                     trait_,
176                                 ))) = ctx.sema.resolve_path(&path_seg.parent_path())
177                                 {
178                                     let arg_idx = arg_list
179                                         .generic_args()
180                                         .filter(|arg| {
181                                             arg.syntax().text_range().end()
182                                                 < ctx.original_token.text_range().start()
183                                         })
184                                         .count();
185
186                                     let n_required_params =
187                                         trait_.type_or_const_param_count(ctx.sema.db, true);
188                                     if arg_idx >= n_required_params {
189                                         trait_
190                                             .items_with_supertraits(ctx.sema.db)
191                                             .into_iter()
192                                             .for_each(|it| {
193                                                 if let hir::AssocItem::TypeAlias(alias) = it {
194                                                     cov_mark::hit!(
195                                                         complete_assoc_type_in_generics_list
196                                                     );
197                                                     acc.add_type_alias_with_eq(ctx, alias);
198                                                 }
199                                             });
200
201                                         let n_params =
202                                             trait_.type_or_const_param_count(ctx.sema.db, false);
203                                         if arg_idx >= n_params {
204                                             return; // only show assoc types
205                                         }
206                                     }
207                                 }
208                             }
209                         }
210                     }
211                 }
212                 _ => {}
213             };
214
215             acc.add_nameref_keywords_with_colon(ctx);
216             ctx.process_all_names(&mut |name, def| {
217                 if scope_def_applicable(def) {
218                     acc.add_path_resolution(ctx, path_ctx, name, def);
219                 }
220             });
221         }
222     }
223 }
224
225 pub(crate) fn complete_ascribed_type(
226     acc: &mut Completions,
227     ctx: &CompletionContext<'_>,
228     path_ctx: &PathCompletionCtx,
229     ascription: &TypeAscriptionTarget,
230 ) -> Option<()> {
231     if !path_ctx.is_trivial_path() {
232         return None;
233     }
234     let x = match ascription {
235         TypeAscriptionTarget::Let(pat) | TypeAscriptionTarget::FnParam(pat) => {
236             ctx.sema.type_of_pat(pat.as_ref()?)
237         }
238         TypeAscriptionTarget::Const(exp) | TypeAscriptionTarget::RetType(exp) => {
239             ctx.sema.type_of_expr(exp.as_ref()?)
240         }
241     }?
242     .adjusted();
243     let ty_string = x.display_source_code(ctx.db, ctx.module.into()).ok()?;
244     acc.add(render_type_inference(ty_string, ctx));
245     None
246 }