]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
Merge commit 'b52fb5234cd7c11ecfae51897a6f7fa52e8777fc' into clippyup
[rust.git] / src / tools / rust-analyzer / crates / ide-completion / src / completions / item_list.rs
1 //! Completion of paths and keywords at item list position.
2
3 use crate::{
4     context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified},
5     CompletionContext, Completions,
6 };
7
8 pub(crate) mod trait_impl;
9
10 pub(crate) fn complete_item_list_in_expr(
11     acc: &mut Completions,
12     ctx: &CompletionContext<'_>,
13     path_ctx: &PathCompletionCtx,
14     expr_ctx: &ExprCtx,
15 ) {
16     if !expr_ctx.in_block_expr {
17         return;
18     }
19     if !path_ctx.is_trivial_path() {
20         return;
21     }
22     add_keywords(acc, ctx, None);
23 }
24
25 pub(crate) fn complete_item_list(
26     acc: &mut Completions,
27     ctx: &CompletionContext<'_>,
28     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
29     kind: &ItemListKind,
30 ) {
31     let _p = profile::span("complete_item_list");
32     if path_ctx.is_trivial_path() {
33         add_keywords(acc, ctx, Some(kind));
34     }
35
36     match qualified {
37         Qualified::With {
38             resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
39             super_chain_len,
40             ..
41         } => {
42             for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
43                 match def {
44                     hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
45                         acc.add_macro(ctx, path_ctx, m, name)
46                     }
47                     hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
48                         acc.add_module(ctx, path_ctx, m, name)
49                     }
50                     _ => (),
51                 }
52             }
53
54             acc.add_super_keyword(ctx, *super_chain_len);
55         }
56         Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
57         Qualified::No if ctx.qualifier_ctx.none() => {
58             ctx.process_all_names(&mut |name, def| match def {
59                 hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
60                     acc.add_macro(ctx, path_ctx, m, name)
61                 }
62                 hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
63                     acc.add_module(ctx, path_ctx, m, name)
64                 }
65                 _ => (),
66             });
67             acc.add_nameref_keywords_with_colon(ctx);
68         }
69         Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {}
70     }
71 }
72
73 fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option<&ItemListKind>) {
74     let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
75
76     let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None);
77     let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait));
78     let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock));
79     let in_trait = matches!(kind, Some(ItemListKind::Trait));
80     let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_)));
81     let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
82     let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
83     let in_block = matches!(kind, None);
84
85     if !in_trait_impl {
86         if ctx.qualifier_ctx.unsafe_tok.is_some() {
87             if in_item_list || in_assoc_non_trait_impl {
88                 add_keyword("fn", "fn $1($2) {\n    $0\n}");
89             }
90             if in_item_list {
91                 add_keyword("trait", "trait $1 {\n    $0\n}");
92                 if no_qualifiers {
93                     add_keyword("impl", "impl $1 {\n    $0\n}");
94                 }
95             }
96             return;
97         }
98
99         if in_item_list {
100             add_keyword("enum", "enum $1 {\n    $0\n}");
101             add_keyword("mod", "mod $0");
102             add_keyword("static", "static $0");
103             add_keyword("struct", "struct $0");
104             add_keyword("trait", "trait $1 {\n    $0\n}");
105             add_keyword("union", "union $1 {\n    $0\n}");
106             add_keyword("use", "use $0");
107             if no_qualifiers {
108                 add_keyword("impl", "impl $1 {\n    $0\n}");
109             }
110         }
111
112         if !in_trait && !in_block && no_qualifiers {
113             add_keyword("pub(crate)", "pub(crate)");
114             add_keyword("pub(super)", "pub(super)");
115             add_keyword("pub", "pub");
116         }
117
118         if in_extern_block {
119             add_keyword("fn", "fn $1($2);");
120         } else {
121             if !in_inherent_impl {
122                 if !in_trait {
123                     add_keyword("extern", "extern $0");
124                 }
125                 add_keyword("type", "type $0");
126             }
127
128             add_keyword("fn", "fn $1($2) {\n    $0\n}");
129             add_keyword("unsafe", "unsafe");
130             add_keyword("const", "const $0");
131         }
132     }
133 }