1 //! `render` module provides utilities for rendering completion suggestions
2 //! into code pieces that will be presented to user.
3
4 pub(crate) mod macro_;
5 pub(crate) mod function;
6 pub(crate) mod const_;
7 pub(crate) mod pattern;
8 pub(crate) mod type_alias;
9 pub(crate) mod variant;
10 pub(crate) mod union_literal;
11 pub(crate) mod literal;
12
13 use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
14 use ide_db::{
15 helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind,
16 };
17 use syntax::{AstNode, SmolStr, SyntaxKind, TextRange};
18
19 use crate::{
20 context::{DotAccess, PathCompletionCtx, PathKind, PatternContext},
21 item::{Builder, CompletionRelevanceTypeMatch},
22 render::{
23 function::render_fn,
24 literal::render_variant_lit,
25 macro_::{render_macro, render_macro_pat},
26 },
27 CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
28 };
29 /// Interface for data and methods required for items rendering.
30 #[derive(Debug, Clone)]
31 pub(crate) struct RenderContext<'a> {
32 completion: &'a CompletionContext<'a>,
33 is_private_editable: bool,
34 import_to_add: Option<LocatedImport>,
35 doc_aliases: Vec<SmolStr>,
36 }
37
38 impl<'a> RenderContext<'a> {
new(completion: &'a CompletionContext<'a>) -> RenderContext<'a>39 pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> {
40 RenderContext {
41 completion,
42 is_private_editable: false,
43 import_to_add: None,
44 doc_aliases: vec![],
45 }
46 }
47
private_editable(mut self, private_editable: bool) -> Self48 pub(crate) fn private_editable(mut self, private_editable: bool) -> Self {
49 self.is_private_editable = private_editable;
50 self
51 }
52
import_to_add(mut self, import_to_add: Option<LocatedImport>) -> Self53 pub(crate) fn import_to_add(mut self, import_to_add: Option<LocatedImport>) -> Self {
54 self.import_to_add = import_to_add;
55 self
56 }
57
doc_aliases(mut self, doc_aliases: Vec<SmolStr>) -> Self58 pub(crate) fn doc_aliases(mut self, doc_aliases: Vec<SmolStr>) -> Self {
59 self.doc_aliases = doc_aliases;
60 self
61 }
62
snippet_cap(&self) -> Option<SnippetCap>63 fn snippet_cap(&self) -> Option<SnippetCap> {
64 self.completion.config.snippet_cap
65 }
66
db(&self) -> &'a RootDatabase67 fn db(&self) -> &'a RootDatabase {
68 self.completion.db
69 }
70
source_range(&self) -> TextRange71 fn source_range(&self) -> TextRange {
72 self.completion.source_range()
73 }
74
completion_relevance(&self) -> CompletionRelevance75 fn completion_relevance(&self) -> CompletionRelevance {
76 CompletionRelevance {
77 is_private_editable: self.is_private_editable,
78 requires_import: self.import_to_add.is_some(),
79 ..Default::default()
80 }
81 }
82
is_immediately_after_macro_bang(&self) -> bool83 fn is_immediately_after_macro_bang(&self) -> bool {
84 self.completion.token.kind() == SyntaxKind::BANG
85 && self
86 .completion
87 .token
88 .parent()
89 .map_or(false, |it| it.kind() == SyntaxKind::MACRO_CALL)
90 }
91
is_deprecated(&self, def: impl HasAttrs) -> bool92 fn is_deprecated(&self, def: impl HasAttrs) -> bool {
93 let attrs = def.attrs(self.db());
94 attrs.by_key("deprecated").exists()
95 }
96
is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool97 fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
98 let db = self.db();
99 let assoc = match as_assoc_item.as_assoc_item(db) {
100 Some(assoc) => assoc,
101 None => return false,
102 };
103
104 let is_assoc_deprecated = match assoc {
105 hir::AssocItem::Function(it) => self.is_deprecated(it),
106 hir::AssocItem::Const(it) => self.is_deprecated(it),
107 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
108 };
109 is_assoc_deprecated
110 || assoc
111 .containing_trait_or_trait_impl(db)
112 .map(|trait_| self.is_deprecated(trait_))
113 .unwrap_or(false)
114 }
115
116 // FIXME: remove this
docs(&self, def: impl HasAttrs) -> Option<hir::Documentation>117 fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
118 def.docs(self.db())
119 }
120 }
121
render_field( ctx: RenderContext<'_>, dot_access: &DotAccess, receiver: Option<hir::Name>, field: hir::Field, ty: &hir::Type, ) -> CompletionItem122 pub(crate) fn render_field(
123 ctx: RenderContext<'_>,
124 dot_access: &DotAccess,
125 receiver: Option<hir::Name>,
126 field: hir::Field,
127 ty: &hir::Type,
128 ) -> CompletionItem {
129 let db = ctx.db();
130 let is_deprecated = ctx.is_deprecated(field);
131 let name = field.name(db);
132 let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str());
133 let mut item = CompletionItem::new(
134 SymbolKind::Field,
135 ctx.source_range(),
136 field_with_receiver(db, receiver.as_ref(), &name),
137 );
138 item.set_relevance(CompletionRelevance {
139 type_match: compute_type_match(ctx.completion, ty),
140 exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
141 ..CompletionRelevance::default()
142 });
143 item.detail(ty.display(db).to_string())
144 .set_documentation(field.docs(db))
145 .set_deprecated(is_deprecated)
146 .lookup_by(name);
147 item.insert_text(field_with_receiver(db, receiver.as_ref(), &escaped_name));
148 if let Some(receiver) = &dot_access.receiver {
149 if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) {
150 if let Some(ref_match) = compute_ref_match(ctx.completion, ty) {
151 item.ref_match(ref_match, original.syntax().text_range().start());
152 }
153 }
154 }
155 item.doc_aliases(ctx.doc_aliases);
156 item.build(db)
157 }
158
field_with_receiver( db: &RootDatabase, receiver: Option<&hir::Name>, field_name: &str, ) -> SmolStr159 fn field_with_receiver(
160 db: &RootDatabase,
161 receiver: Option<&hir::Name>,
162 field_name: &str,
163 ) -> SmolStr {
164 receiver.map_or_else(
165 || field_name.into(),
166 |receiver| format!("{}.{field_name}", receiver.display(db)).into(),
167 )
168 }
169
render_tuple_field( ctx: RenderContext<'_>, receiver: Option<hir::Name>, field: usize, ty: &hir::Type, ) -> CompletionItem170 pub(crate) fn render_tuple_field(
171 ctx: RenderContext<'_>,
172 receiver: Option<hir::Name>,
173 field: usize,
174 ty: &hir::Type,
175 ) -> CompletionItem {
176 let mut item = CompletionItem::new(
177 SymbolKind::Field,
178 ctx.source_range(),
179 field_with_receiver(ctx.db(), receiver.as_ref(), &field.to_string()),
180 );
181 item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string());
182 item.build(ctx.db())
183 }
184
render_type_inference( ty_string: String, ctx: &CompletionContext<'_>, ) -> CompletionItem185 pub(crate) fn render_type_inference(
186 ty_string: String,
187 ctx: &CompletionContext<'_>,
188 ) -> CompletionItem {
189 let mut builder =
190 CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string);
191 builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() });
192 builder.build(ctx.db)
193 }
194
render_path_resolution( ctx: RenderContext<'_>, path_ctx: &PathCompletionCtx, local_name: hir::Name, resolution: ScopeDef, ) -> Builder195 pub(crate) fn render_path_resolution(
196 ctx: RenderContext<'_>,
197 path_ctx: &PathCompletionCtx,
198 local_name: hir::Name,
199 resolution: ScopeDef,
200 ) -> Builder {
201 render_resolution_path(ctx, path_ctx, local_name, None, resolution)
202 }
203
render_pattern_resolution( ctx: RenderContext<'_>, pattern_ctx: &PatternContext, local_name: hir::Name, resolution: ScopeDef, ) -> Builder204 pub(crate) fn render_pattern_resolution(
205 ctx: RenderContext<'_>,
206 pattern_ctx: &PatternContext,
207 local_name: hir::Name,
208 resolution: ScopeDef,
209 ) -> Builder {
210 render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution)
211 }
212
render_resolution_with_import( ctx: RenderContext<'_>, path_ctx: &PathCompletionCtx, import_edit: LocatedImport, ) -> Option<Builder>213 pub(crate) fn render_resolution_with_import(
214 ctx: RenderContext<'_>,
215 path_ctx: &PathCompletionCtx,
216 import_edit: LocatedImport,
217 ) -> Option<Builder> {
218 let resolution = ScopeDef::from(import_edit.original_item);
219 let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
220 //this now just renders the alias text, but we need to find the aliases earlier and call this with the alias instead
221 let doc_aliases = ctx.completion.doc_aliases_in_scope(resolution);
222 let ctx = ctx.doc_aliases(doc_aliases);
223 Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution))
224 }
225
render_resolution_with_import_pat( ctx: RenderContext<'_>, pattern_ctx: &PatternContext, import_edit: LocatedImport, ) -> Option<Builder>226 pub(crate) fn render_resolution_with_import_pat(
227 ctx: RenderContext<'_>,
228 pattern_ctx: &PatternContext,
229 import_edit: LocatedImport,
230 ) -> Option<Builder> {
231 let resolution = ScopeDef::from(import_edit.original_item);
232 let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
233 Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution))
234 }
235
scope_def_to_name( resolution: ScopeDef, ctx: &RenderContext<'_>, import_edit: &LocatedImport, ) -> Option<hir::Name>236 fn scope_def_to_name(
237 resolution: ScopeDef,
238 ctx: &RenderContext<'_>,
239 import_edit: &LocatedImport,
240 ) -> Option<hir::Name> {
241 Some(match resolution {
242 ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
243 ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
244 ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
245 _ => item_name(ctx.db(), import_edit.original_item)?,
246 })
247 }
248
render_resolution_pat( ctx: RenderContext<'_>, pattern_ctx: &PatternContext, local_name: hir::Name, import_to_add: Option<LocatedImport>, resolution: ScopeDef, ) -> Builder249 fn render_resolution_pat(
250 ctx: RenderContext<'_>,
251 pattern_ctx: &PatternContext,
252 local_name: hir::Name,
253 import_to_add: Option<LocatedImport>,
254 resolution: ScopeDef,
255 ) -> Builder {
256 let _p = profile::span("render_resolution");
257 use hir::ModuleDef::*;
258
259 match resolution {
260 ScopeDef::ModuleDef(Macro(mac)) => {
261 let ctx = ctx.import_to_add(import_to_add);
262 return render_macro_pat(ctx, pattern_ctx, local_name, mac);
263 }
264 _ => (),
265 }
266
267 render_resolution_simple_(ctx, &local_name, import_to_add, resolution)
268 }
269
render_resolution_path( ctx: RenderContext<'_>, path_ctx: &PathCompletionCtx, local_name: hir::Name, import_to_add: Option<LocatedImport>, resolution: ScopeDef, ) -> Builder270 fn render_resolution_path(
271 ctx: RenderContext<'_>,
272 path_ctx: &PathCompletionCtx,
273 local_name: hir::Name,
274 import_to_add: Option<LocatedImport>,
275 resolution: ScopeDef,
276 ) -> Builder {
277 let _p = profile::span("render_resolution");
278 use hir::ModuleDef::*;
279
280 match resolution {
281 ScopeDef::ModuleDef(Macro(mac)) => {
282 let ctx = ctx.import_to_add(import_to_add);
283 return render_macro(ctx, path_ctx, local_name, mac);
284 }
285 ScopeDef::ModuleDef(Function(func)) => {
286 let ctx = ctx.import_to_add(import_to_add);
287 return render_fn(ctx, path_ctx, Some(local_name), func);
288 }
289 ScopeDef::ModuleDef(Variant(var)) => {
290 let ctx = ctx.clone().import_to_add(import_to_add.clone());
291 if let Some(item) =
292 render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None)
293 {
294 return item;
295 }
296 }
297 _ => (),
298 }
299
300 let completion = ctx.completion;
301 let cap = ctx.snippet_cap();
302 let db = completion.db;
303 let config = completion.config;
304
305 let name = local_name.to_smol_str();
306 let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);
307 if local_name.is_escaped() {
308 item.insert_text(local_name.to_smol_str());
309 }
310 // Add `<>` for generic types
311 let type_path_no_ty_args = matches!(
312 path_ctx,
313 PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. }
314 ) && config.callable.is_some();
315 if type_path_no_ty_args {
316 if let Some(cap) = cap {
317 let has_non_default_type_params = match resolution {
318 ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db),
319 ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => {
320 it.has_non_default_type_params(db)
321 }
322 _ => false,
323 };
324
325 if has_non_default_type_params {
326 cov_mark::hit!(inserts_angle_brackets_for_generics);
327 item.lookup_by(name.clone())
328 .label(SmolStr::from_iter([&name, "<…>"]))
329 .trigger_call_info()
330 .insert_snippet(cap, format!("{}<$0>", local_name.display(db)));
331 }
332 }
333 }
334 if let ScopeDef::Local(local) = resolution {
335 let ty = local.ty(db);
336 if !ty.is_unknown() {
337 item.detail(ty.display(db).to_string());
338 }
339
340 item.set_relevance(CompletionRelevance {
341 type_match: compute_type_match(completion, &ty),
342 exact_name_match: compute_exact_name_match(completion, &name),
343 is_local: true,
344 ..CompletionRelevance::default()
345 });
346
347 path_ref_match(completion, path_ctx, &ty, &mut item);
348 };
349 item
350 }
351
render_resolution_simple_( ctx: RenderContext<'_>, local_name: &hir::Name, import_to_add: Option<LocatedImport>, resolution: ScopeDef, ) -> Builder352 fn render_resolution_simple_(
353 ctx: RenderContext<'_>,
354 local_name: &hir::Name,
355 import_to_add: Option<LocatedImport>,
356 resolution: ScopeDef,
357 ) -> Builder {
358 let _p = profile::span("render_resolution");
359
360 let db = ctx.db();
361 let ctx = ctx.import_to_add(import_to_add);
362 let kind = res_to_kind(resolution);
363
364 let mut item =
365 CompletionItem::new(kind, ctx.source_range(), local_name.unescaped().to_smol_str());
366 item.set_relevance(ctx.completion_relevance())
367 .set_documentation(scope_def_docs(db, resolution))
368 .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
369
370 if let Some(import_to_add) = ctx.import_to_add {
371 item.add_import(import_to_add);
372 }
373
374 item.doc_aliases(ctx.doc_aliases);
375 item
376 }
377
res_to_kind(resolution: ScopeDef) -> CompletionItemKind378 fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind {
379 use hir::ModuleDef::*;
380 match resolution {
381 ScopeDef::Unknown => CompletionItemKind::UnresolvedReference,
382 ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function),
383 ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
384 ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro),
385 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
386 ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
387 hir::Adt::Struct(_) => SymbolKind::Struct,
388 hir::Adt::Union(_) => SymbolKind::Union,
389 hir::Adt::Enum(_) => SymbolKind::Enum,
390 }),
391 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
392 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
393 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
394 ScopeDef::ModuleDef(TraitAlias(..)) => {
395 CompletionItemKind::SymbolKind(SymbolKind::TraitAlias)
396 }
397 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias),
398 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
399 ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
400 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
401 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
402 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
403 }),
404 ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
405 ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
406 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
407 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
408 }
409 }
410 }
411
scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation>412 fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
413 use hir::ModuleDef::*;
414 match resolution {
415 ScopeDef::ModuleDef(Module(it)) => it.docs(db),
416 ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
417 ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
418 ScopeDef::ModuleDef(Const(it)) => it.docs(db),
419 ScopeDef::ModuleDef(Static(it)) => it.docs(db),
420 ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
421 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
422 _ => None,
423 }
424 }
425
scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool426 fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool {
427 match resolution {
428 ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(it),
429 ScopeDef::GenericParam(it) => ctx.is_deprecated(it),
430 ScopeDef::AdtSelfType(it) => ctx.is_deprecated(it),
431 _ => false,
432 }
433 }
434
compute_type_match( ctx: &CompletionContext<'_>, completion_ty: &hir::Type, ) -> Option<CompletionRelevanceTypeMatch>435 fn compute_type_match(
436 ctx: &CompletionContext<'_>,
437 completion_ty: &hir::Type,
438 ) -> Option<CompletionRelevanceTypeMatch> {
439 let expected_type = ctx.expected_type.as_ref()?;
440
441 // We don't ever consider unit type to be an exact type match, since
442 // nearly always this is not meaningful to the user.
443 if expected_type.is_unit() {
444 return None;
445 }
446
447 if completion_ty == expected_type {
448 Some(CompletionRelevanceTypeMatch::Exact)
449 } else if expected_type.could_unify_with(ctx.db, completion_ty) {
450 Some(CompletionRelevanceTypeMatch::CouldUnify)
451 } else {
452 None
453 }
454 }
455
compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str) -> bool456 fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str) -> bool {
457 ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name)
458 }
459
compute_ref_match( ctx: &CompletionContext<'_>, completion_ty: &hir::Type, ) -> Option<hir::Mutability>460 fn compute_ref_match(
461 ctx: &CompletionContext<'_>,
462 completion_ty: &hir::Type,
463 ) -> Option<hir::Mutability> {
464 let expected_type = ctx.expected_type.as_ref()?;
465 if completion_ty != expected_type {
466 let expected_type_without_ref = expected_type.remove_ref()?;
467 if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) {
468 cov_mark::hit!(suggest_ref);
469 let mutability = if expected_type.is_mutable_reference() {
470 hir::Mutability::Mut
471 } else {
472 hir::Mutability::Shared
473 };
474 return Some(mutability);
475 };
476 }
477 None
478 }
479
path_ref_match( completion: &CompletionContext<'_>, path_ctx: &PathCompletionCtx, ty: &hir::Type, item: &mut Builder, )480 fn path_ref_match(
481 completion: &CompletionContext<'_>,
482 path_ctx: &PathCompletionCtx,
483 ty: &hir::Type,
484 item: &mut Builder,
485 ) {
486 if let Some(original_path) = &path_ctx.original_path {
487 // At least one char was typed by the user already, in that case look for the original path
488 if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) {
489 if let Some(ref_match) = compute_ref_match(completion, ty) {
490 item.ref_match(ref_match, original_path.syntax().text_range().start());
491 }
492 }
493 } else {
494 // completion requested on an empty identifier, there is no path here yet.
495 // FIXME: This might create inconsistent completions where we show a ref match in macro inputs
496 // as long as nothing was typed yet
497 if let Some(ref_match) = compute_ref_match(completion, ty) {
498 item.ref_match(ref_match, completion.position.offset);
499 }
500 }
501 }
502
503 #[cfg(test)]
504 mod tests {
505 use std::cmp;
506
507 use expect_test::{expect, Expect};
508 use ide_db::SymbolKind;
509 use itertools::Itertools;
510
511 use crate::{
512 item::CompletionRelevanceTypeMatch,
513 tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
514 CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
515 };
516
517 #[track_caller]
check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect)518 fn check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect) {
519 let actual = do_completion(ra_fixture, kind.into());
520 expect.assert_debug_eq(&actual);
521 }
522
523 #[track_caller]
check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect)524 fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
525 let actual: Vec<_> =
526 kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();
527 expect.assert_debug_eq(&actual);
528 }
529
530 #[track_caller]
check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect)531 fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
532 let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
533 actual.retain(|it| kinds.contains(&it.kind));
534 actual.sort_by_key(|it| cmp::Reverse(it.relevance.score()));
535 check_relevance_(actual, expect);
536 }
537
538 #[track_caller]
check_relevance(ra_fixture: &str, expect: Expect)539 fn check_relevance(ra_fixture: &str, expect: Expect) {
540 let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
541 actual.retain(|it| it.kind != CompletionItemKind::Snippet);
542 actual.retain(|it| it.kind != CompletionItemKind::Keyword);
543 actual.retain(|it| it.kind != CompletionItemKind::BuiltinType);
544 actual.sort_by_key(|it| cmp::Reverse(it.relevance.score()));
545 check_relevance_(actual, expect);
546 }
547
548 #[track_caller]
check_relevance_(actual: Vec<CompletionItem>, expect: Expect)549 fn check_relevance_(actual: Vec<CompletionItem>, expect: Expect) {
550 let actual = actual
551 .into_iter()
552 .flat_map(|it| {
553 let mut items = vec![];
554
555 let tag = it.kind.tag();
556 let relevance = display_relevance(it.relevance);
557 items.push(format!("{tag} {} {relevance}\n", it.label));
558
559 if let Some((label, _indel, relevance)) = it.ref_match() {
560 let relevance = display_relevance(relevance);
561
562 items.push(format!("{tag} {label} {relevance}\n"));
563 }
564
565 items
566 })
567 .collect::<String>();
568
569 expect.assert_eq(&actual);
570
571 fn display_relevance(relevance: CompletionRelevance) -> String {
572 let relevance_factors = vec![
573 (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"),
574 (
575 relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify),
576 "type_could_unify",
577 ),
578 (relevance.exact_name_match, "name"),
579 (relevance.is_local, "local"),
580 (
581 relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact),
582 "snippet",
583 ),
584 (relevance.is_op_method, "op_method"),
585 (relevance.requires_import, "requires_import"),
586 ]
587 .into_iter()
588 .filter_map(|(cond, desc)| if cond { Some(desc) } else { None })
589 .join("+");
590
591 format!("[{relevance_factors}]")
592 }
593 }
594
595 #[test]
enum_detail_includes_record_fields()596 fn enum_detail_includes_record_fields() {
597 check(
598 r#"
599 enum Foo { Foo { x: i32, y: i32 } }
600
601 fn main() { Foo::Fo$0 }
602 "#,
603 SymbolKind::Variant,
604 expect![[r#"
605 [
606 CompletionItem {
607 label: "Foo {…}",
608 source_range: 54..56,
609 delete: 54..56,
610 insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
611 kind: SymbolKind(
612 Variant,
613 ),
614 lookup: "Foo{}",
615 detail: "Foo { x: i32, y: i32 }",
616 trigger_call_info: true,
617 },
618 ]
619 "#]],
620 );
621 }
622
623 #[test]
enum_detail_includes_tuple_fields()624 fn enum_detail_includes_tuple_fields() {
625 check(
626 r#"
627 enum Foo { Foo (i32, i32) }
628
629 fn main() { Foo::Fo$0 }
630 "#,
631 SymbolKind::Variant,
632 expect![[r#"
633 [
634 CompletionItem {
635 label: "Foo(…)",
636 source_range: 46..48,
637 delete: 46..48,
638 insert: "Foo(${1:()}, ${2:()})$0",
639 kind: SymbolKind(
640 Variant,
641 ),
642 lookup: "Foo()",
643 detail: "Foo(i32, i32)",
644 trigger_call_info: true,
645 },
646 ]
647 "#]],
648 );
649 }
650
651 #[test]
fn_detail_includes_args_and_return_type()652 fn fn_detail_includes_args_and_return_type() {
653 check(
654 r#"
655 fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
656
657 fn main() { fo$0 }
658 "#,
659 SymbolKind::Function,
660 expect![[r#"
661 [
662 CompletionItem {
663 label: "foo(…)",
664 source_range: 68..70,
665 delete: 68..70,
666 insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
667 kind: SymbolKind(
668 Function,
669 ),
670 lookup: "foo",
671 detail: "fn(u32, u32, T) -> (u32, T)",
672 trigger_call_info: true,
673 },
674 CompletionItem {
675 label: "main()",
676 source_range: 68..70,
677 delete: 68..70,
678 insert: "main()$0",
679 kind: SymbolKind(
680 Function,
681 ),
682 lookup: "main",
683 detail: "fn()",
684 },
685 ]
686 "#]],
687 );
688 }
689
690 #[test]
enum_detail_just_name_for_unit()691 fn enum_detail_just_name_for_unit() {
692 check(
693 r#"
694 enum Foo { Foo }
695
696 fn main() { Foo::Fo$0 }
697 "#,
698 SymbolKind::Variant,
699 expect![[r#"
700 [
701 CompletionItem {
702 label: "Foo",
703 source_range: 35..37,
704 delete: 35..37,
705 insert: "Foo$0",
706 kind: SymbolKind(
707 Variant,
708 ),
709 detail: "Foo",
710 trigger_call_info: true,
711 },
712 ]
713 "#]],
714 );
715 }
716
717 #[test]
lookup_enums_by_two_qualifiers()718 fn lookup_enums_by_two_qualifiers() {
719 check_kinds(
720 r#"
721 mod m {
722 pub enum Spam { Foo, Bar(i32) }
723 }
724 fn main() { let _: m::Spam = S$0 }
725 "#,
726 &[
727 CompletionItemKind::SymbolKind(SymbolKind::Function),
728 CompletionItemKind::SymbolKind(SymbolKind::Module),
729 CompletionItemKind::SymbolKind(SymbolKind::Variant),
730 ],
731 expect![[r#"
732 [
733 CompletionItem {
734 label: "main()",
735 source_range: 75..76,
736 delete: 75..76,
737 insert: "main()$0",
738 kind: SymbolKind(
739 Function,
740 ),
741 lookup: "main",
742 detail: "fn()",
743 },
744 CompletionItem {
745 label: "m",
746 source_range: 75..76,
747 delete: 75..76,
748 insert: "m",
749 kind: SymbolKind(
750 Module,
751 ),
752 },
753 CompletionItem {
754 label: "m::Spam::Bar(…)",
755 source_range: 75..76,
756 delete: 75..76,
757 insert: "m::Spam::Bar(${1:()})$0",
758 kind: SymbolKind(
759 Variant,
760 ),
761 lookup: "Spam::Bar()",
762 detail: "m::Spam::Bar(i32)",
763 relevance: CompletionRelevance {
764 exact_name_match: false,
765 type_match: Some(
766 Exact,
767 ),
768 is_local: false,
769 is_item_from_trait: false,
770 is_name_already_imported: false,
771 requires_import: false,
772 is_op_method: false,
773 is_private_editable: false,
774 postfix_match: None,
775 is_definite: false,
776 },
777 trigger_call_info: true,
778 },
779 CompletionItem {
780 label: "m::Spam::Foo",
781 source_range: 75..76,
782 delete: 75..76,
783 insert: "m::Spam::Foo$0",
784 kind: SymbolKind(
785 Variant,
786 ),
787 lookup: "Spam::Foo",
788 detail: "m::Spam::Foo",
789 relevance: CompletionRelevance {
790 exact_name_match: false,
791 type_match: Some(
792 Exact,
793 ),
794 is_local: false,
795 is_item_from_trait: false,
796 is_name_already_imported: false,
797 requires_import: false,
798 is_op_method: false,
799 is_private_editable: false,
800 postfix_match: None,
801 is_definite: false,
802 },
803 trigger_call_info: true,
804 },
805 ]
806 "#]],
807 )
808 }
809
810 #[test]
sets_deprecated_flag_in_items()811 fn sets_deprecated_flag_in_items() {
812 check(
813 r#"
814 #[deprecated]
815 fn something_deprecated() {}
816
817 fn main() { som$0 }
818 "#,
819 SymbolKind::Function,
820 expect![[r#"
821 [
822 CompletionItem {
823 label: "main()",
824 source_range: 56..59,
825 delete: 56..59,
826 insert: "main()$0",
827 kind: SymbolKind(
828 Function,
829 ),
830 lookup: "main",
831 detail: "fn()",
832 },
833 CompletionItem {
834 label: "something_deprecated()",
835 source_range: 56..59,
836 delete: 56..59,
837 insert: "something_deprecated()$0",
838 kind: SymbolKind(
839 Function,
840 ),
841 lookup: "something_deprecated",
842 detail: "fn()",
843 deprecated: true,
844 },
845 ]
846 "#]],
847 );
848
849 check(
850 r#"
851 struct A { #[deprecated] the_field: u32 }
852 fn foo() { A { the$0 } }
853 "#,
854 SymbolKind::Field,
855 expect![[r#"
856 [
857 CompletionItem {
858 label: "the_field",
859 source_range: 57..60,
860 delete: 57..60,
861 insert: "the_field",
862 kind: SymbolKind(
863 Field,
864 ),
865 detail: "u32",
866 deprecated: true,
867 relevance: CompletionRelevance {
868 exact_name_match: false,
869 type_match: Some(
870 CouldUnify,
871 ),
872 is_local: false,
873 is_item_from_trait: false,
874 is_name_already_imported: false,
875 requires_import: false,
876 is_op_method: false,
877 is_private_editable: false,
878 postfix_match: None,
879 is_definite: false,
880 },
881 },
882 ]
883 "#]],
884 );
885 }
886
887 #[test]
renders_docs()888 fn renders_docs() {
889 check_kinds(
890 r#"
891 struct S {
892 /// Field docs
893 foo:
894 }
895 impl S {
896 /// Method docs
897 fn bar(self) { self.$0 }
898 }"#,
899 &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
900 expect![[r#"
901 [
902 CompletionItem {
903 label: "bar()",
904 source_range: 94..94,
905 delete: 94..94,
906 insert: "bar()$0",
907 kind: Method,
908 lookup: "bar",
909 detail: "fn(self)",
910 documentation: Documentation(
911 "Method docs",
912 ),
913 },
914 CompletionItem {
915 label: "foo",
916 source_range: 94..94,
917 delete: 94..94,
918 insert: "foo",
919 kind: SymbolKind(
920 Field,
921 ),
922 detail: "{unknown}",
923 documentation: Documentation(
924 "Field docs",
925 ),
926 },
927 ]
928 "#]],
929 );
930
931 check_kinds(
932 r#"
933 use self::my$0;
934
935 /// mod docs
936 mod my { }
937
938 /// enum docs
939 enum E {
940 /// variant docs
941 V
942 }
943 use self::E::*;
944 "#,
945 &[
946 CompletionItemKind::SymbolKind(SymbolKind::Module),
947 CompletionItemKind::SymbolKind(SymbolKind::Variant),
948 CompletionItemKind::SymbolKind(SymbolKind::Enum),
949 ],
950 expect![[r#"
951 [
952 CompletionItem {
953 label: "my",
954 source_range: 10..12,
955 delete: 10..12,
956 insert: "my",
957 kind: SymbolKind(
958 Module,
959 ),
960 documentation: Documentation(
961 "mod docs",
962 ),
963 },
964 CompletionItem {
965 label: "V",
966 source_range: 10..12,
967 delete: 10..12,
968 insert: "V$0",
969 kind: SymbolKind(
970 Variant,
971 ),
972 detail: "V",
973 documentation: Documentation(
974 "variant docs",
975 ),
976 trigger_call_info: true,
977 },
978 CompletionItem {
979 label: "E",
980 source_range: 10..12,
981 delete: 10..12,
982 insert: "E",
983 kind: SymbolKind(
984 Enum,
985 ),
986 documentation: Documentation(
987 "enum docs",
988 ),
989 },
990 ]
991 "#]],
992 )
993 }
994
995 #[test]
dont_render_attrs()996 fn dont_render_attrs() {
997 check(
998 r#"
999 struct S;
1000 impl S {
1001 #[inline]
1002 fn the_method(&self) { }
1003 }
1004 fn foo(s: S) { s.$0 }
1005 "#,
1006 CompletionItemKind::Method,
1007 expect![[r#"
1008 [
1009 CompletionItem {
1010 label: "the_method()",
1011 source_range: 81..81,
1012 delete: 81..81,
1013 insert: "the_method()$0",
1014 kind: Method,
1015 lookup: "the_method",
1016 detail: "fn(&self)",
1017 },
1018 ]
1019 "#]],
1020 )
1021 }
1022
1023 #[test]
no_call_parens_if_fn_ptr_needed()1024 fn no_call_parens_if_fn_ptr_needed() {
1025 cov_mark::check!(no_call_parens_if_fn_ptr_needed);
1026 check_edit(
1027 "foo",
1028 r#"
1029 fn foo(foo: u8, bar: u8) {}
1030 struct ManualVtable { f: fn(u8, u8) }
1031
1032 fn main() -> ManualVtable {
1033 ManualVtable { f: f$0 }
1034 }
1035 "#,
1036 r#"
1037 fn foo(foo: u8, bar: u8) {}
1038 struct ManualVtable { f: fn(u8, u8) }
1039
1040 fn main() -> ManualVtable {
1041 ManualVtable { f: foo }
1042 }
1043 "#,
1044 );
1045 check_edit(
1046 "type",
1047 r#"
1048 struct RawIdentTable { r#type: u32 }
1049
1050 fn main() -> RawIdentTable {
1051 RawIdentTable { t$0: 42 }
1052 }
1053 "#,
1054 r#"
1055 struct RawIdentTable { r#type: u32 }
1056
1057 fn main() -> RawIdentTable {
1058 RawIdentTable { r#type: 42 }
1059 }
1060 "#,
1061 );
1062 }
1063
1064 #[test]
no_parens_in_use_item()1065 fn no_parens_in_use_item() {
1066 check_edit(
1067 "foo",
1068 r#"
1069 mod m { pub fn foo() {} }
1070 use crate::m::f$0;
1071 "#,
1072 r#"
1073 mod m { pub fn foo() {} }
1074 use crate::m::foo;
1075 "#,
1076 );
1077 }
1078
1079 #[test]
no_parens_in_call()1080 fn no_parens_in_call() {
1081 check_edit(
1082 "foo",
1083 r#"
1084 fn foo(x: i32) {}
1085 fn main() { f$0(); }
1086 "#,
1087 r#"
1088 fn foo(x: i32) {}
1089 fn main() { foo(); }
1090 "#,
1091 );
1092 check_edit(
1093 "foo",
1094 r#"
1095 struct Foo;
1096 impl Foo { fn foo(&self){} }
1097 fn f(foo: &Foo) { foo.f$0(); }
1098 "#,
1099 r#"
1100 struct Foo;
1101 impl Foo { fn foo(&self){} }
1102 fn f(foo: &Foo) { foo.foo(); }
1103 "#,
1104 );
1105 }
1106
1107 #[test]
inserts_angle_brackets_for_generics()1108 fn inserts_angle_brackets_for_generics() {
1109 cov_mark::check!(inserts_angle_brackets_for_generics);
1110 check_edit(
1111 "Vec",
1112 r#"
1113 struct Vec<T> {}
1114 fn foo(xs: Ve$0)
1115 "#,
1116 r#"
1117 struct Vec<T> {}
1118 fn foo(xs: Vec<$0>)
1119 "#,
1120 );
1121 check_edit(
1122 "Vec",
1123 r#"
1124 type Vec<T> = (T,);
1125 fn foo(xs: Ve$0)
1126 "#,
1127 r#"
1128 type Vec<T> = (T,);
1129 fn foo(xs: Vec<$0>)
1130 "#,
1131 );
1132 check_edit(
1133 "Vec",
1134 r#"
1135 struct Vec<T = i128> {}
1136 fn foo(xs: Ve$0)
1137 "#,
1138 r#"
1139 struct Vec<T = i128> {}
1140 fn foo(xs: Vec)
1141 "#,
1142 );
1143 check_edit(
1144 "Vec",
1145 r#"
1146 struct Vec<T> {}
1147 fn foo(xs: Ve$0<i128>)
1148 "#,
1149 r#"
1150 struct Vec<T> {}
1151 fn foo(xs: Vec<i128>)
1152 "#,
1153 );
1154 }
1155
1156 #[test]
active_param_relevance()1157 fn active_param_relevance() {
1158 check_relevance(
1159 r#"
1160 struct S { foo: i64, bar: u32, baz: u32 }
1161 fn test(bar: u32) { }
1162 fn foo(s: S) { test(s.$0) }
1163 "#,
1164 expect![[r#"
1165 fd bar [type+name]
1166 fd baz [type]
1167 fd foo []
1168 "#]],
1169 );
1170 }
1171
1172 #[test]
record_field_relevances()1173 fn record_field_relevances() {
1174 check_relevance(
1175 r#"
1176 struct A { foo: i64, bar: u32, baz: u32 }
1177 struct B { x: (), y: f32, bar: u32 }
1178 fn foo(a: A) { B { bar: a.$0 }; }
1179 "#,
1180 expect![[r#"
1181 fd bar [type+name]
1182 fd baz [type]
1183 fd foo []
1184 "#]],
1185 )
1186 }
1187
1188 #[test]
record_field_and_call_relevances()1189 fn record_field_and_call_relevances() {
1190 check_relevance(
1191 r#"
1192 struct A { foo: i64, bar: u32, baz: u32 }
1193 struct B { x: (), y: f32, bar: u32 }
1194 fn f(foo: i64) { }
1195 fn foo(a: A) { B { bar: f(a.$0) }; }
1196 "#,
1197 expect![[r#"
1198 fd foo [type+name]
1199 fd bar []
1200 fd baz []
1201 "#]],
1202 );
1203 check_relevance(
1204 r#"
1205 struct A { foo: i64, bar: u32, baz: u32 }
1206 struct B { x: (), y: f32, bar: u32 }
1207 fn f(foo: i64) { }
1208 fn foo(a: A) { f(B { bar: a.$0 }); }
1209 "#,
1210 expect![[r#"
1211 fd bar [type+name]
1212 fd baz [type]
1213 fd foo []
1214 "#]],
1215 );
1216 }
1217
1218 #[test]
prioritize_exact_ref_match()1219 fn prioritize_exact_ref_match() {
1220 check_relevance(
1221 r#"
1222 struct WorldSnapshot { _f: () };
1223 fn go(world: &WorldSnapshot) { go(w$0) }
1224 "#,
1225 expect![[r#"
1226 lc world [type+name+local]
1227 st WorldSnapshot {…} []
1228 st &WorldSnapshot {…} [type]
1229 st WorldSnapshot []
1230 fn go(…) []
1231 "#]],
1232 );
1233 }
1234
1235 #[test]
too_many_arguments()1236 fn too_many_arguments() {
1237 cov_mark::check!(too_many_arguments);
1238 check_relevance(
1239 r#"
1240 struct Foo;
1241 fn f(foo: &Foo) { f(foo, w$0) }
1242 "#,
1243 expect![[r#"
1244 lc foo [local]
1245 st Foo []
1246 fn f(…) []
1247 "#]],
1248 );
1249 }
1250
1251 #[test]
score_fn_type_and_name_match()1252 fn score_fn_type_and_name_match() {
1253 check_relevance(
1254 r#"
1255 struct A { bar: u8 }
1256 fn baz() -> u8 { 0 }
1257 fn bar() -> u8 { 0 }
1258 fn f() { A { bar: b$0 }; }
1259 "#,
1260 expect![[r#"
1261 fn bar() [type+name]
1262 fn baz() [type]
1263 st A []
1264 fn f() []
1265 "#]],
1266 );
1267 }
1268
1269 #[test]
score_method_type_and_name_match()1270 fn score_method_type_and_name_match() {
1271 check_relevance(
1272 r#"
1273 fn baz(aaa: u32){}
1274 struct Foo;
1275 impl Foo {
1276 fn aaa(&self) -> u32 { 0 }
1277 fn bbb(&self) -> u32 { 0 }
1278 fn ccc(&self) -> u64 { 0 }
1279 }
1280 fn f() {
1281 baz(Foo.$0
1282 }
1283 "#,
1284 expect![[r#"
1285 me aaa() [type+name]
1286 me bbb() [type]
1287 me ccc() []
1288 "#]],
1289 );
1290 }
1291
1292 #[test]
score_method_name_match_only()1293 fn score_method_name_match_only() {
1294 check_relevance(
1295 r#"
1296 fn baz(aaa: u32){}
1297 struct Foo;
1298 impl Foo {
1299 fn aaa(&self) -> u64 { 0 }
1300 }
1301 fn f() {
1302 baz(Foo.$0
1303 }
1304 "#,
1305 expect![[r#"
1306 me aaa() [name]
1307 "#]],
1308 );
1309 }
1310
1311 #[test]
suggest_ref_mut()1312 fn suggest_ref_mut() {
1313 cov_mark::check!(suggest_ref);
1314 check_relevance(
1315 r#"
1316 struct S;
1317 fn foo(s: &mut S) {}
1318 fn main() {
1319 let mut s = S;
1320 foo($0);
1321 }
1322 "#,
1323 expect![[r#"
1324 lc s [name+local]
1325 lc &mut s [type+name+local]
1326 st S []
1327 st &mut S [type]
1328 st S []
1329 fn foo(…) []
1330 fn main() []
1331 "#]],
1332 );
1333 check_relevance(
1334 r#"
1335 struct S;
1336 fn foo(s: &mut S) {}
1337 fn main() {
1338 let mut s = S;
1339 foo(&mut $0);
1340 }
1341 "#,
1342 expect![[r#"
1343 lc s [type+name+local]
1344 st S [type]
1345 st S []
1346 fn foo(…) []
1347 fn main() []
1348 "#]],
1349 );
1350 check_relevance(
1351 r#"
1352 struct S;
1353 fn foo(s: &mut S) {}
1354 fn main() {
1355 let mut ssss = S;
1356 foo(&mut s$0);
1357 }
1358 "#,
1359 expect![[r#"
1360 lc ssss [type+local]
1361 st S [type]
1362 st S []
1363 fn foo(…) []
1364 fn main() []
1365 "#]],
1366 );
1367 }
1368
1369 #[test]
suggest_deref()1370 fn suggest_deref() {
1371 check_relevance(
1372 r#"
1373 //- minicore: deref
1374 struct S;
1375 struct T(S);
1376
1377 impl core::ops::Deref for T {
1378 type Target = S;
1379
1380 fn deref(&self) -> &Self::Target {
1381 &self.0
1382 }
1383 }
1384
1385 fn foo(s: &S) {}
1386
1387 fn main() {
1388 let t = T(S);
1389 let m = 123;
1390
1391 foo($0);
1392 }
1393 "#,
1394 expect![[r#"
1395 lc m [local]
1396 lc t [local]
1397 lc &t [type+local]
1398 st S []
1399 st &S [type]
1400 st S []
1401 st T []
1402 fn foo(…) []
1403 fn main() []
1404 md core []
1405 "#]],
1406 )
1407 }
1408
1409 #[test]
suggest_deref_mut()1410 fn suggest_deref_mut() {
1411 check_relevance(
1412 r#"
1413 //- minicore: deref_mut
1414 struct S;
1415 struct T(S);
1416
1417 impl core::ops::Deref for T {
1418 type Target = S;
1419
1420 fn deref(&self) -> &Self::Target {
1421 &self.0
1422 }
1423 }
1424
1425 impl core::ops::DerefMut for T {
1426 fn deref_mut(&mut self) -> &mut Self::Target {
1427 &mut self.0
1428 }
1429 }
1430
1431 fn foo(s: &mut S) {}
1432
1433 fn main() {
1434 let t = T(S);
1435 let m = 123;
1436
1437 foo($0);
1438 }
1439 "#,
1440 expect![[r#"
1441 lc m [local]
1442 lc t [local]
1443 lc &mut t [type+local]
1444 st S []
1445 st &mut S [type]
1446 st S []
1447 st T []
1448 fn foo(…) []
1449 fn main() []
1450 md core []
1451 "#]],
1452 )
1453 }
1454
1455 #[test]
locals()1456 fn locals() {
1457 check_relevance(
1458 r#"
1459 fn foo(bar: u32) {
1460 let baz = 0;
1461
1462 f$0
1463 }
1464 "#,
1465 expect![[r#"
1466 lc baz [local]
1467 lc bar [local]
1468 fn foo(…) []
1469 "#]],
1470 );
1471 }
1472
1473 #[test]
enum_owned()1474 fn enum_owned() {
1475 check_relevance(
1476 r#"
1477 enum Foo { A, B }
1478 fn foo() {
1479 bar($0);
1480 }
1481 fn bar(t: Foo) {}
1482 "#,
1483 expect![[r#"
1484 ev Foo::A [type]
1485 ev Foo::B [type]
1486 en Foo []
1487 fn bar(…) []
1488 fn foo() []
1489 "#]],
1490 );
1491 }
1492
1493 #[test]
enum_ref()1494 fn enum_ref() {
1495 check_relevance(
1496 r#"
1497 enum Foo { A, B }
1498 fn foo() {
1499 bar($0);
1500 }
1501 fn bar(t: &Foo) {}
1502 "#,
1503 expect![[r#"
1504 ev Foo::A []
1505 ev &Foo::A [type]
1506 ev Foo::B []
1507 ev &Foo::B [type]
1508 en Foo []
1509 fn bar(…) []
1510 fn foo() []
1511 "#]],
1512 );
1513 }
1514
1515 #[test]
suggest_deref_fn_ret()1516 fn suggest_deref_fn_ret() {
1517 check_relevance(
1518 r#"
1519 //- minicore: deref
1520 struct S;
1521 struct T(S);
1522
1523 impl core::ops::Deref for T {
1524 type Target = S;
1525
1526 fn deref(&self) -> &Self::Target {
1527 &self.0
1528 }
1529 }
1530
1531 fn foo(s: &S) {}
1532 fn bar() -> T {}
1533
1534 fn main() {
1535 foo($0);
1536 }
1537 "#,
1538 expect![[r#"
1539 st S []
1540 st &S [type]
1541 st S []
1542 st T []
1543 fn bar() []
1544 fn &bar() [type]
1545 fn foo(…) []
1546 fn main() []
1547 md core []
1548 "#]],
1549 )
1550 }
1551
1552 #[test]
op_function_relevances()1553 fn op_function_relevances() {
1554 check_relevance(
1555 r#"
1556 #[lang = "sub"]
1557 trait Sub {
1558 fn sub(self, other: Self) -> Self { self }
1559 }
1560 impl Sub for u32 {}
1561 fn foo(a: u32) { a.$0 }
1562 "#,
1563 expect![[r#"
1564 me sub(…) (as Sub) [op_method]
1565 "#]],
1566 );
1567 check_relevance(
1568 r#"
1569 struct Foo;
1570 impl Foo {
1571 fn new() -> Self {}
1572 }
1573 #[lang = "eq"]
1574 pub trait PartialEq<Rhs: ?Sized = Self> {
1575 fn eq(&self, other: &Rhs) -> bool;
1576 fn ne(&self, other: &Rhs) -> bool;
1577 }
1578
1579 impl PartialEq for Foo {}
1580 fn main() {
1581 Foo::$0
1582 }
1583 "#,
1584 expect![[r#"
1585 fn new() []
1586 me eq(…) (as PartialEq) [op_method]
1587 me ne(…) (as PartialEq) [op_method]
1588 "#]],
1589 );
1590 }
1591
1592 #[test]
struct_field_method_ref()1593 fn struct_field_method_ref() {
1594 check_kinds(
1595 r#"
1596 struct Foo { bar: u32 }
1597 impl Foo { fn baz(&self) -> u32 { 0 } }
1598
1599 fn foo(f: Foo) { let _: &u32 = f.b$0 }
1600 "#,
1601 &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
1602 expect![[r#"
1603 [
1604 CompletionItem {
1605 label: "baz()",
1606 source_range: 98..99,
1607 delete: 98..99,
1608 insert: "baz()$0",
1609 kind: Method,
1610 lookup: "baz",
1611 detail: "fn(&self) -> u32",
1612 ref_match: "&@96",
1613 },
1614 CompletionItem {
1615 label: "bar",
1616 source_range: 98..99,
1617 delete: 98..99,
1618 insert: "bar",
1619 kind: SymbolKind(
1620 Field,
1621 ),
1622 detail: "u32",
1623 ref_match: "&@96",
1624 },
1625 ]
1626 "#]],
1627 );
1628 }
1629
1630 #[test]
qualified_path_ref()1631 fn qualified_path_ref() {
1632 check_kinds(
1633 r#"
1634 struct S;
1635
1636 struct T;
1637 impl T {
1638 fn foo() -> S {}
1639 }
1640
1641 fn bar(s: &S) {}
1642
1643 fn main() {
1644 bar(T::$0);
1645 }
1646 "#,
1647 &[CompletionItemKind::SymbolKind(SymbolKind::Function)],
1648 expect![[r#"
1649 [
1650 CompletionItem {
1651 label: "foo()",
1652 source_range: 95..95,
1653 delete: 95..95,
1654 insert: "foo()$0",
1655 kind: SymbolKind(
1656 Function,
1657 ),
1658 lookup: "foo",
1659 detail: "fn() -> S",
1660 ref_match: "&@92",
1661 },
1662 ]
1663 "#]],
1664 );
1665 }
1666
1667 #[test]
generic_enum()1668 fn generic_enum() {
1669 check_relevance(
1670 r#"
1671 enum Foo<T> { A(T), B }
1672 // bar() should not be an exact type match
1673 // because the generic parameters are different
1674 fn bar() -> Foo<u8> { Foo::B }
1675 // FIXME baz() should be an exact type match
1676 // because the types could unify, but it currently
1677 // is not. This is due to the T here being
1678 // TyKind::Placeholder rather than TyKind::Missing.
1679 fn baz<T>() -> Foo<T> { Foo::B }
1680 fn foo() {
1681 let foo: Foo<u32> = Foo::B;
1682 let _: Foo<u32> = f$0;
1683 }
1684 "#,
1685 expect![[r#"
1686 lc foo [type+local]
1687 ev Foo::A(…) [type_could_unify]
1688 ev Foo::B [type_could_unify]
1689 fn foo() []
1690 en Foo []
1691 fn bar() []
1692 fn baz() []
1693 "#]],
1694 );
1695 }
1696
1697 #[test]
postfix_exact_match_is_high_priority()1698 fn postfix_exact_match_is_high_priority() {
1699 cov_mark::check!(postfix_exact_match_is_high_priority);
1700 check_relevance_for_kinds(
1701 r#"
1702 mod ops {
1703 pub trait Not {
1704 type Output;
1705 fn not(self) -> Self::Output;
1706 }
1707
1708 impl Not for bool {
1709 type Output = bool;
1710 fn not(self) -> bool { if self { false } else { true }}
1711 }
1712 }
1713
1714 fn main() {
1715 let _: bool = (9 > 2).not$0;
1716 }
1717 "#,
1718 &[CompletionItemKind::Snippet, CompletionItemKind::Method],
1719 expect![[r#"
1720 sn not [snippet]
1721 me not() (use ops::Not) [type_could_unify+requires_import]
1722 sn if []
1723 sn while []
1724 sn ref []
1725 sn refm []
1726 sn unsafe []
1727 sn match []
1728 sn box []
1729 sn dbg []
1730 sn dbgr []
1731 sn call []
1732 "#]],
1733 );
1734 }
1735
1736 #[test]
postfix_inexact_match_is_low_priority()1737 fn postfix_inexact_match_is_low_priority() {
1738 cov_mark::check!(postfix_inexact_match_is_low_priority);
1739 check_relevance_for_kinds(
1740 r#"
1741 struct S;
1742 impl S {
1743 fn f(&self) {}
1744 }
1745 fn main() {
1746 S.$0
1747 }
1748 "#,
1749 &[CompletionItemKind::Snippet, CompletionItemKind::Method],
1750 expect![[r#"
1751 me f() []
1752 sn ref []
1753 sn refm []
1754 sn unsafe []
1755 sn match []
1756 sn box []
1757 sn dbg []
1758 sn dbgr []
1759 sn call []
1760 sn let []
1761 sn letm []
1762 "#]],
1763 );
1764 }
1765
1766 #[test]
flyimport_reduced_relevance()1767 fn flyimport_reduced_relevance() {
1768 check_relevance(
1769 r#"
1770 mod std {
1771 pub mod io {
1772 pub trait BufRead {}
1773 pub struct BufReader;
1774 pub struct BufWriter;
1775 }
1776 }
1777 struct Buffer;
1778
1779 fn f() {
1780 Buf$0
1781 }
1782 "#,
1783 expect![[r#"
1784 st Buffer []
1785 fn f() []
1786 md std []
1787 tt BufRead (use std::io::BufRead) [requires_import]
1788 st BufReader (use std::io::BufReader) [requires_import]
1789 st BufWriter (use std::io::BufWriter) [requires_import]
1790 "#]],
1791 );
1792 }
1793
1794 #[test]
completes_struct_with_raw_identifier()1795 fn completes_struct_with_raw_identifier() {
1796 check_edit(
1797 "type",
1798 r#"
1799 mod m { pub struct r#type {} }
1800 fn main() {
1801 let r#type = m::t$0;
1802 }
1803 "#,
1804 r#"
1805 mod m { pub struct r#type {} }
1806 fn main() {
1807 let r#type = m::r#type;
1808 }
1809 "#,
1810 )
1811 }
1812
1813 #[test]
completes_fn_with_raw_identifier()1814 fn completes_fn_with_raw_identifier() {
1815 check_edit(
1816 "type",
1817 r#"
1818 mod m { pub fn r#type {} }
1819 fn main() {
1820 m::t$0
1821 }
1822 "#,
1823 r#"
1824 mod m { pub fn r#type {} }
1825 fn main() {
1826 m::r#type()$0
1827 }
1828 "#,
1829 )
1830 }
1831
1832 #[test]
completes_macro_with_raw_identifier()1833 fn completes_macro_with_raw_identifier() {
1834 check_edit(
1835 "let!",
1836 r#"
1837 macro_rules! r#let { () => {} }
1838 fn main() {
1839 $0
1840 }
1841 "#,
1842 r#"
1843 macro_rules! r#let { () => {} }
1844 fn main() {
1845 r#let!($0)
1846 }
1847 "#,
1848 )
1849 }
1850
1851 #[test]
completes_variant_with_raw_identifier()1852 fn completes_variant_with_raw_identifier() {
1853 check_edit(
1854 "type",
1855 r#"
1856 enum A { r#type }
1857 fn main() {
1858 let a = A::t$0
1859 }
1860 "#,
1861 r#"
1862 enum A { r#type }
1863 fn main() {
1864 let a = A::r#type$0
1865 }
1866 "#,
1867 )
1868 }
1869
1870 #[test]
completes_field_with_raw_identifier()1871 fn completes_field_with_raw_identifier() {
1872 check_edit(
1873 "fn",
1874 r#"
1875 mod r#type {
1876 pub struct r#struct {
1877 pub r#fn: u32
1878 }
1879 }
1880
1881 fn main() {
1882 let a = r#type::r#struct {};
1883 a.$0
1884 }
1885 "#,
1886 r#"
1887 mod r#type {
1888 pub struct r#struct {
1889 pub r#fn: u32
1890 }
1891 }
1892
1893 fn main() {
1894 let a = r#type::r#struct {};
1895 a.r#fn
1896 }
1897 "#,
1898 )
1899 }
1900
1901 #[test]
completes_const_with_raw_identifier()1902 fn completes_const_with_raw_identifier() {
1903 check_edit(
1904 "type",
1905 r#"
1906 struct r#struct {}
1907 impl r#struct { pub const r#type: u8 = 1; }
1908 fn main() {
1909 r#struct::t$0
1910 }
1911 "#,
1912 r#"
1913 struct r#struct {}
1914 impl r#struct { pub const r#type: u8 = 1; }
1915 fn main() {
1916 r#struct::r#type
1917 }
1918 "#,
1919 )
1920 }
1921
1922 #[test]
completes_type_alias_with_raw_identifier()1923 fn completes_type_alias_with_raw_identifier() {
1924 check_edit(
1925 "type type",
1926 r#"
1927 struct r#struct {}
1928 trait r#trait { type r#type; }
1929 impl r#trait for r#struct { type t$0 }
1930 "#,
1931 r#"
1932 struct r#struct {}
1933 trait r#trait { type r#type; }
1934 impl r#trait for r#struct { type r#type = $0; }
1935 "#,
1936 )
1937 }
1938
1939 #[test]
field_access_includes_self()1940 fn field_access_includes_self() {
1941 check_edit(
1942 "length",
1943 r#"
1944 struct S {
1945 length: i32
1946 }
1947
1948 impl S {
1949 fn some_fn(&self) {
1950 let l = len$0
1951 }
1952 }
1953 "#,
1954 r#"
1955 struct S {
1956 length: i32
1957 }
1958
1959 impl S {
1960 fn some_fn(&self) {
1961 let l = self.length
1962 }
1963 }
1964 "#,
1965 )
1966 }
1967 }
1968