]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
Rollup merge of #101967 - jmillikin:linux-abstract-socket-addr, r=joshtriplett
[rust.git] / src / tools / rust-analyzer / crates / ide-completion / src / completions / pattern.rs
1 //! Completes constants and paths in unqualified patterns.
2
3 use hir::{db::DefDatabase, AssocItem, ScopeDef};
4 use syntax::ast::Pat;
5
6 use crate::{
7     context::{PathCompletionCtx, PatternContext, PatternRefutability, Qualified},
8     CompletionContext, Completions,
9 };
10
11 /// Completes constants and paths in unqualified patterns.
12 pub(crate) fn complete_pattern(
13     acc: &mut Completions,
14     ctx: &CompletionContext<'_>,
15     pattern_ctx: &PatternContext,
16 ) {
17     match pattern_ctx.parent_pat.as_ref() {
18         Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
19         Some(Pat::RefPat(r)) => {
20             if r.mut_token().is_none() {
21                 acc.add_keyword(ctx, "mut");
22             }
23         }
24         _ => {
25             let tok = ctx.token.text_range().start();
26             match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) {
27                 (None, None) => {
28                     acc.add_keyword(ctx, "ref");
29                     acc.add_keyword(ctx, "mut");
30                 }
31                 (None, Some(m)) if tok < m.text_range().start() => {
32                     acc.add_keyword(ctx, "ref");
33                 }
34                 (Some(r), None) if tok > r.text_range().end() => {
35                     acc.add_keyword(ctx, "mut");
36                 }
37                 _ => (),
38             }
39         }
40     }
41
42     if pattern_ctx.record_pat.is_some() {
43         return;
44     }
45
46     let refutable = pattern_ctx.refutability == PatternRefutability::Refutable;
47     let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
48
49     if let Some(hir::Adt::Enum(e)) =
50         ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
51     {
52         if refutable || single_variant_enum(e) {
53             super::enum_variants_with_paths(
54                 acc,
55                 ctx,
56                 e,
57                 &pattern_ctx.impl_,
58                 |acc, ctx, variant, path| {
59                     acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path);
60                 },
61             );
62         }
63     }
64
65     // FIXME: ideally, we should look at the type we are matching against and
66     // suggest variants + auto-imports
67     ctx.process_all_names(&mut |name, res| {
68         let add_simple_path = match res {
69             hir::ScopeDef::ModuleDef(def) => match def {
70                 hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
71                     acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
72                     true
73                 }
74                 hir::ModuleDef::Variant(variant)
75                     if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
76                 {
77                     acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
78                     true
79                 }
80                 hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
81                 hir::ModuleDef::Const(..) => refutable,
82                 hir::ModuleDef::Module(..) => true,
83                 hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db),
84                 _ => false,
85             },
86             hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
87                 Some(hir::Adt::Struct(strukt)) => {
88                     acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
89                     true
90                 }
91                 Some(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
92                 Some(hir::Adt::Union(_)) => true,
93                 _ => false,
94             },
95             ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => true,
96             ScopeDef::GenericParam(_)
97             | ScopeDef::AdtSelfType(_)
98             | ScopeDef::Local(_)
99             | ScopeDef::Label(_)
100             | ScopeDef::Unknown => false,
101         };
102         if add_simple_path {
103             acc.add_pattern_resolution(ctx, pattern_ctx, name, res);
104         }
105     });
106 }
107
108 pub(crate) fn complete_pattern_path(
109     acc: &mut Completions,
110     ctx: &CompletionContext<'_>,
111     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
112 ) {
113     match qualified {
114         Qualified::With { resolution: Some(resolution), super_chain_len, .. } => {
115             acc.add_super_keyword(ctx, *super_chain_len);
116
117             match resolution {
118                 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
119                     let module_scope = module.scope(ctx.db, Some(ctx.module));
120                     for (name, def) in module_scope {
121                         let add_resolution = match def {
122                             ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
123                                 mac.is_fn_like(ctx.db)
124                             }
125                             ScopeDef::ModuleDef(_) => true,
126                             _ => false,
127                         };
128
129                         if add_resolution {
130                             acc.add_path_resolution(ctx, path_ctx, name, def);
131                         }
132                     }
133                 }
134                 res => {
135                     let ty = match res {
136                         hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
137                         hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
138                         hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(s))) => {
139                             s.ty(ctx.db)
140                         }
141                         hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
142                             e.ty(ctx.db)
143                         }
144                         hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
145                             u.ty(ctx.db)
146                         }
147                         hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => ty.ty(ctx.db),
148                         hir::PathResolution::Def(hir::ModuleDef::TypeAlias(ty)) => ty.ty(ctx.db),
149                         _ => return,
150                     };
151
152                     if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
153                         acc.add_enum_variants(ctx, path_ctx, e);
154                     }
155
156                     ctx.iterate_path_candidates(&ty, |item| match item {
157                         AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta),
158                         AssocItem::Const(c) => acc.add_const(ctx, c),
159                         _ => {}
160                     });
161                 }
162             }
163         }
164         Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
165         Qualified::No => {
166             // this will only be hit if there are brackets or braces, otherwise this will be parsed as an ident pattern
167             ctx.process_all_names(&mut |name, res| {
168                 // FIXME: we should check what kind of pattern we are in and filter accordingly
169                 let add_completion = match res {
170                     ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
171                     ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true,
172                     ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true,
173                     ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
174                     ScopeDef::ImplSelfType(_) => true,
175                     _ => false,
176                 };
177                 if add_completion {
178                     acc.add_path_resolution(ctx, path_ctx, name, res);
179                 }
180             });
181
182             acc.add_nameref_keywords_with_colon(ctx);
183         }
184         Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
185     }
186 }