ide_completion/completions/
use_.rs1use hir::ScopeDef;
4use ide_db::{FxHashSet, SymbolKind};
5use syntax::{AstNode, ast, format_smolstr};
6
7use crate::{
8 CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
9 context::{CompletionContext, PathCompletionCtx, Qualified},
10 item::Builder,
11};
12
13pub(crate) fn complete_use_path(
14 acc: &mut Completions,
15 ctx: &CompletionContext<'_>,
16 path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx<'_>,
17 name_ref: &Option<ast::NameRef>,
18) {
19 match qualified {
20 Qualified::With { path, resolution: Some(resolution), super_chain_len } => {
21 acc.add_super_keyword(ctx, *super_chain_len);
22
23 let not_preceded_by_self = *use_tree_parent
25 && !matches!(
26 path.segment().and_then(|it| it.kind()),
27 Some(ast::PathSegmentKind::SelfKw)
28 );
29 if not_preceded_by_self {
30 acc.add_keyword(ctx, "self");
31 }
32
33 let mut already_imported_names = FxHashSet::default();
34 if let Some(list) = ctx.token.parent_ancestors().find_map(ast::UseTreeList::cast) {
35 let use_tree = list.parent_use_tree();
36 if use_tree.path().as_ref() == Some(path) {
37 for tree in list.use_trees().filter(|tree| tree.is_simple_path()) {
38 if let Some(name) = tree.path().and_then(|path| path.as_single_name_ref()) {
39 already_imported_names.insert(name.to_string());
40 }
41 }
42 }
43 }
44
45 match resolution {
46 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
47 let module_scope = module.scope(ctx.db, Some(ctx.module));
48 let unknown_is_current = |name: &hir::Name| {
49 matches!(
50 name_ref,
51 Some(name_ref) if name_ref.syntax().text() == name.as_str()
52 )
53 };
54 for (name, def) in module_scope {
55 if let (Some(attrs), Some(defining_crate)) =
56 (def.attrs(ctx.db), def.krate(ctx.db))
57 && (!ctx.check_stability(Some(&attrs))
58 || ctx.is_doc_hidden(&attrs, defining_crate))
59 {
60 continue;
61 }
62 let is_name_already_imported =
63 already_imported_names.contains(name.as_str());
64
65 let add_resolution = match def {
66 ScopeDef::Unknown if unknown_is_current(&name) => {
67 cov_mark::hit!(dont_complete_current_use);
69 continue;
70 }
71 ScopeDef::ModuleDef(_) | ScopeDef::Unknown => true,
72 _ => false,
73 };
74
75 if add_resolution {
76 let mut builder = Builder::from_resolution(ctx, path_ctx, name, def);
77 builder.with_relevance(|r| CompletionRelevance {
78 is_name_already_imported,
79 ..r
80 });
81 acc.add(builder.build(ctx.db));
82 }
83 }
84 }
85 hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
86 cov_mark::hit!(enum_plain_qualified_use_tree);
87 acc.add_enum_variants(ctx, path_ctx, *e);
88 }
89 _ => {}
90 }
91 }
92 Qualified::Absolute => {
94 cov_mark::hit!(use_tree_crate_roots_only);
95 acc.add_crate_roots(ctx, path_ctx);
96 }
97 Qualified::No => {
99 cov_mark::hit!(unqualified_path_selected_only);
100 ctx.process_all_names(&mut |name, res, doc_aliases| {
101 match res {
102 ScopeDef::ModuleDef(hir::ModuleDef::Module(module)) => {
103 acc.add_module(ctx, path_ctx, module, name, doc_aliases);
104 }
105 ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
106 let is_builtin =
108 res.krate(ctx.db).is_some_and(|krate| krate.is_builtin(ctx.db));
109
110 if !is_builtin {
111 let item = CompletionItem::new(
112 CompletionItemKind::SymbolKind(SymbolKind::Enum),
113 ctx.source_range(),
114 format_smolstr!(
115 "{}::",
116 e.name(ctx.db).display(ctx.db, ctx.edition)
117 ),
118 ctx.edition,
119 );
120 acc.add(item.build(ctx.db));
121 }
122 }
123 _ => {}
124 };
125 });
126 acc.add_nameref_keywords_with_colon(ctx);
127 }
128 Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {}
129 }
130}