1 //! Completion for use trees
4 use ide_db::{FxHashSet, SymbolKind};
5 use syntax::{ast, AstNode};
8 context::{CompletionContext, PathCompletionCtx, Qualified},
10 CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
13 pub(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>,
20 Qualified::With { path, resolution: Some(resolution), super_chain_len } => {
21 acc.add_super_keyword(ctx, *super_chain_len);
23 // only show `self` in a new use-tree when the qualifier doesn't end in self
24 let not_preceded_by_self = *use_tree_parent
26 path.segment().and_then(|it| it.kind()),
27 Some(ast::PathSegmentKind::SelfKw)
29 if not_preceded_by_self {
30 acc.add_keyword(ctx, "self");
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());
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| {
51 Some(name_ref) if name_ref.syntax().text() == name.to_smol_str().as_str()
54 for (name, def) in module_scope {
55 let is_name_already_imported = name
57 .map_or(false, |text| already_imported_names.contains(text.as_str()));
59 let add_resolution = match def {
60 ScopeDef::Unknown if unknown_is_current(&name) => {
61 // for `use self::foo$0`, don't suggest `foo` as a completion
62 cov_mark::hit!(dont_complete_current_use);
65 ScopeDef::ModuleDef(_) | ScopeDef::Unknown => true,
70 let mut builder = Builder::from_resolution(ctx, path_ctx, name, def);
71 builder.set_relevance(CompletionRelevance {
72 is_name_already_imported,
75 acc.add(builder.build());
79 hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
80 cov_mark::hit!(enum_plain_qualified_use_tree);
81 acc.add_enum_variants(ctx, path_ctx, *e);
86 // fresh use tree with leading colon2, only show crate roots
87 Qualified::Absolute => {
88 cov_mark::hit!(use_tree_crate_roots_only);
89 acc.add_crate_roots(ctx, path_ctx);
91 // only show modules and non-std enum in a fresh UseTree
93 cov_mark::hit!(unqualified_path_selected_only);
94 ctx.process_all_names(&mut |name, res| {
96 ScopeDef::ModuleDef(hir::ModuleDef::Module(module)) => {
97 acc.add_module(ctx, path_ctx, module, name);
99 ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
100 // exclude prelude enum
102 res.krate(ctx.db).map_or(false, |krate| krate.is_builtin(ctx.db));
105 let item = CompletionItem::new(
106 CompletionItemKind::SymbolKind(SymbolKind::Enum),
108 format!("{}::", e.name(ctx.db)),
110 acc.add(item.build());
116 acc.add_nameref_keywords_with_colon(ctx);
118 Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {}