]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
bump version to 1.80.1+dfsg1-1~bpo12+pve1
[rustc.git] / src / tools / rust-analyzer / crates / ide-completion / src / completions / expr.rs
CommitLineData
064997fb
FG
1//! Completion of names from the current scope in expression position.
2
31ef2f64 3use hir::{ImportPathConfig, ScopeDef};
f2b60f7d 4use syntax::ast;
064997fb
FG
5
6use crate::{
f2b60f7d 7 completions::record::add_default_update,
c620b35d 8 context::{BreakableKind, PathCompletionCtx, PathExprCtx, Qualified},
064997fb
FG
9 CompletionContext, Completions,
10};
11
12pub(crate) fn complete_expr_path(
13 acc: &mut Completions,
14 ctx: &CompletionContext<'_>,
15 path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
c620b35d 16 expr_ctx: &PathExprCtx,
064997fb 17) {
c620b35d 18 let _p = tracing::span!(tracing::Level::INFO, "complete_expr_path").entered();
064997fb
FG
19 if !ctx.qualifier_ctx.none() {
20 return;
21 }
22
c620b35d 23 let &PathExprCtx {
064997fb 24 in_block_expr,
c620b35d 25 in_breakable,
064997fb
FG
26 after_if_expr,
27 in_condition,
28 incomplete_let,
29 ref ref_expr_parent,
30 ref is_func_update,
31 ref innermost_ret_ty,
32 ref impl_,
33 in_match_guard,
34 ..
35 } = expr_ctx;
36
37 let wants_mut_token =
38 ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
39
40 let scope_def_applicable = |def| match def {
41 ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false,
42 ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
43 _ => true,
44 };
45
46 let add_assoc_item = |acc: &mut Completions, item| match item {
47 hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
48 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
49 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
50 };
51
52 match qualified {
53 Qualified::TypeAnchor { ty: None, trait_: None } => ctx
54 .traits_in_scope()
55 .iter()
56 .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
57 .for_each(|item| add_assoc_item(acc, item)),
58 Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
59 trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
60 }
61 Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
62 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
63 cov_mark::hit!(completes_variant_through_alias);
64 acc.add_enum_variants(ctx, path_ctx, e);
65 }
66
9c376795 67 ctx.iterate_path_candidates(ty, |item| {
064997fb
FG
68 add_assoc_item(acc, item);
69 });
70
71 // Iterate assoc types separately
72 ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
73 if let hir::AssocItem::TypeAlias(ty) = item {
74 acc.add_type_alias(ctx, ty)
75 }
76 None::<()>
77 });
78 }
79 Qualified::With { resolution: None, .. } => {}
80 Qualified::With { resolution: Some(resolution), .. } => {
81 // Add associated types on type parameters and `Self`.
82 ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
83 acc.add_type_alias(ctx, alias);
84 None::<()>
85 });
86 match resolution {
87 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
88 let module_scope = module.scope(ctx.db, Some(ctx.module));
89 for (name, def) in module_scope {
90 if scope_def_applicable(def) {
fe692bf9
FG
91 acc.add_path_resolution(
92 ctx,
93 path_ctx,
94 name,
95 def,
96 ctx.doc_aliases_in_scope(def),
97 );
064997fb
FG
98 }
99 }
100 }
101 hir::PathResolution::Def(
102 def @ (hir::ModuleDef::Adt(_)
103 | hir::ModuleDef::TypeAlias(_)
104 | hir::ModuleDef::BuiltinType(_)),
105 ) => {
106 let ty = match def {
107 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
108 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
109 hir::ModuleDef::BuiltinType(builtin) => {
110 cov_mark::hit!(completes_primitive_assoc_const);
111 builtin.ty(ctx.db)
112 }
113 _ => return,
114 };
115
116 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
117 cov_mark::hit!(completes_variant_through_alias);
118 acc.add_enum_variants(ctx, path_ctx, e);
119 }
120
121 // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
122 // (where AssocType is defined on a trait, not an inherent impl)
123
124 ctx.iterate_path_candidates(&ty, |item| {
125 add_assoc_item(acc, item);
126 });
127
128 // Iterate assoc types separately
129 ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
130 if let hir::AssocItem::TypeAlias(ty) = item {
131 acc.add_type_alias(ctx, ty)
132 }
133 None::<()>
134 });
135 }
136 hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
137 // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
138 for item in t.items(ctx.db) {
139 add_assoc_item(acc, item);
140 }
141 }
142 hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
143 let ty = match resolution {
144 hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
145 hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
146 _ => return,
147 };
148
149 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
150 cov_mark::hit!(completes_variant_through_self);
151 acc.add_enum_variants(ctx, path_ctx, e);
152 }
153
154 ctx.iterate_path_candidates(&ty, |item| {
155 add_assoc_item(acc, item);
156 });
157 }
158 _ => (),
159 }
160 }
161 Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
162 Qualified::No => {
163 acc.add_nameref_keywords_with_colon(ctx);
164 if let Some(adt) =
165 ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
166 {
167 let self_ty = (|| ctx.sema.to_def(impl_.as_ref()?)?.self_ty(ctx.db).as_adt())();
168 let complete_self = self_ty == Some(adt);
169
170 match adt {
171 hir::Adt::Struct(strukt) => {
172 let path = ctx
173 .module
31ef2f64 174 .find_path(
2b03887a
FG
175 ctx.db,
176 hir::ModuleDef::from(strukt),
31ef2f64
FG
177 ImportPathConfig {
178 prefer_no_std: ctx.config.prefer_no_std,
179 prefer_prelude: ctx.config.prefer_prelude,
180 },
2b03887a 181 )
064997fb
FG
182 .filter(|it| it.len() > 1);
183
184 acc.add_struct_literal(ctx, path_ctx, strukt, path, None);
185
186 if complete_self {
187 acc.add_struct_literal(
188 ctx,
189 path_ctx,
190 strukt,
191 None,
192 Some(hir::known::SELF_TYPE),
193 );
194 }
195 }
196 hir::Adt::Union(un) => {
197 let path = ctx
198 .module
31ef2f64 199 .find_path(
2b03887a
FG
200 ctx.db,
201 hir::ModuleDef::from(un),
31ef2f64
FG
202 ImportPathConfig {
203 prefer_no_std: ctx.config.prefer_no_std,
204 prefer_prelude: ctx.config.prefer_prelude,
205 },
2b03887a 206 )
064997fb
FG
207 .filter(|it| it.len() > 1);
208
209 acc.add_union_literal(ctx, un, path, None);
210 if complete_self {
211 acc.add_union_literal(ctx, un, None, Some(hir::known::SELF_TYPE));
212 }
213 }
214 hir::Adt::Enum(e) => {
215 super::enum_variants_with_paths(
216 acc,
217 ctx,
218 e,
219 impl_,
220 |acc, ctx, variant, path| {
221 acc.add_qualified_enum_variant(ctx, path_ctx, variant, path)
222 },
223 );
224 }
225 }
226 }
fe692bf9 227 ctx.process_all_names(&mut |name, def, doc_aliases| match def {
064997fb
FG
228 ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
229 let assocs = t.items_with_supertraits(ctx.db);
230 match &*assocs {
231 // traits with no assoc items are unusable as expressions since
232 // there is no associated item path that can be constructed with them
233 [] => (),
234 // FIXME: Render the assoc item with the trait qualified
fe692bf9 235 &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases),
064997fb 236 // FIXME: Append `::` to the thing here, since a trait on its own won't work
fe692bf9 237 [..] => acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases),
064997fb
FG
238 }
239 }
fe692bf9
FG
240 _ if scope_def_applicable(def) => {
241 acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases)
242 }
064997fb
FG
243 _ => (),
244 });
245
f2b60f7d
FG
246 match is_func_update {
247 Some(record_expr) => {
248 let ty = ctx.sema.type_of_expr(&ast::Expr::RecordExpr(record_expr.clone()));
064997fb 249
f2b60f7d
FG
250 match ty.as_ref().and_then(|t| t.original.as_adt()) {
251 Some(hir::Adt::Union(_)) => (),
252 _ => {
253 cov_mark::hit!(functional_update);
254 let missing_fields =
255 ctx.sema.record_literal_missing_fields(record_expr);
256 if !missing_fields.is_empty() {
257 add_default_update(acc, ctx, ty);
258 }
259 }
260 };
064997fb 261 }
f2b60f7d
FG
262 None => {
263 let mut add_keyword = |kw, snippet| {
264 acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet)
265 };
064997fb 266
f2b60f7d
FG
267 if !in_block_expr {
268 add_keyword("unsafe", "unsafe {\n $0\n}");
269 }
270 add_keyword("match", "match $1 {\n $0\n}");
271 add_keyword("while", "while $1 {\n $0\n}");
272 add_keyword("while let", "while let $1 = $2 {\n $0\n}");
273 add_keyword("loop", "loop {\n $0\n}");
274 if in_match_guard {
275 add_keyword("if", "if $0");
276 } else {
277 add_keyword("if", "if $1 {\n $0\n}");
278 }
279 add_keyword("if let", "if let $1 = $2 {\n $0\n}");
280 add_keyword("for", "for $1 in $2 {\n $0\n}");
281 add_keyword("true", "true");
282 add_keyword("false", "false");
064997fb 283
f2b60f7d
FG
284 if in_condition || in_block_expr {
285 add_keyword("let", "let");
286 }
064997fb 287
f2b60f7d
FG
288 if after_if_expr {
289 add_keyword("else", "else {\n $0\n}");
290 add_keyword("else if", "else if $1 {\n $0\n}");
291 }
064997fb 292
f2b60f7d
FG
293 if wants_mut_token {
294 add_keyword("mut", "mut ");
295 }
296
c620b35d 297 if in_breakable != BreakableKind::None {
f2b60f7d
FG
298 if in_block_expr {
299 add_keyword("continue", "continue;");
300 add_keyword("break", "break;");
301 } else {
302 add_keyword("continue", "continue");
303 add_keyword("break", "break");
304 }
064997fb 305 }
064997fb 306
f2b60f7d
FG
307 if let Some(ret_ty) = innermost_ret_ty {
308 add_keyword(
309 "return",
310 match (ret_ty.is_unit(), in_block_expr) {
311 (true, true) => {
312 cov_mark::hit!(return_unit_block);
313 "return;"
314 }
315 (true, false) => {
316 cov_mark::hit!(return_unit_no_block);
317 "return"
318 }
319 (false, true) => {
320 cov_mark::hit!(return_value_block);
321 "return $0;"
322 }
323 (false, false) => {
324 cov_mark::hit!(return_value_no_block);
325 "return $0"
326 }
327 },
328 );
329 }
064997fb
FG
330 }
331 }
332 }
333 }
334}
c620b35d
FG
335
336pub(crate) fn complete_expr(acc: &mut Completions, ctx: &CompletionContext<'_>) {
337 let _p = tracing::span!(tracing::Level::INFO, "complete_expr").entered();
338
339 if !ctx.config.enable_term_search {
340 return;
341 }
342
343 if !ctx.qualifier_ctx.none() {
344 return;
345 }
346
347 if let Some(ty) = &ctx.expected_type {
348 // Ignore unit types as they are not very interesting
349 if ty.is_unit() || ty.is_unknown() {
350 return;
351 }
352
353 let term_search_ctx = hir::term_search::TermSearchCtx {
354 sema: &ctx.sema,
355 scope: &ctx.scope,
356 goal: ty.clone(),
357 config: hir::term_search::TermSearchConfig {
358 enable_borrowcheck: false,
359 many_alternatives_threshold: 1,
31ef2f64 360 fuel: 200,
c620b35d
FG
361 },
362 };
363 let exprs = hir::term_search::term_search(&term_search_ctx);
364 for expr in exprs {
365 // Expand method calls
366 match expr {
367 hir::term_search::Expr::Method { func, generics, target, params }
368 if target.is_many() =>
369 {
370 let target_ty = target.ty(ctx.db);
371 let term_search_ctx =
372 hir::term_search::TermSearchCtx { goal: target_ty, ..term_search_ctx };
373 let target_exprs = hir::term_search::term_search(&term_search_ctx);
374
375 for expr in target_exprs {
376 let expanded_expr = hir::term_search::Expr::Method {
377 func,
378 generics: generics.clone(),
379 target: Box::new(expr),
380 params: params.clone(),
381 };
382
383 acc.add_expr(ctx, &expanded_expr)
384 }
385 }
386 _ => acc.add_expr(ctx, &expr),
387 }
388 }
389 }
390}