aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion')
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs26
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs12
-rw-r--r--crates/ide_completion/src/render.rs386
3 files changed, 210 insertions, 214 deletions
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 0b0a81410..58d4dd9ee 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -657,6 +657,32 @@ fn main() { let _ = crate::$0 }
657 } 657 }
658 658
659 #[test] 659 #[test]
660 fn does_not_complete_non_fn_macros() {
661 check(
662 r#"
663mod m {
664 #[rustc_builtin_macro]
665 pub macro Clone {}
666}
667
668fn f() {m::$0}
669"#,
670 expect![[r#""#]],
671 );
672 check(
673 r#"
674mod m {
675 #[rustc_builtin_macro]
676 pub macro bench {}
677}
678
679fn f() {m::$0}
680"#,
681 expect![[r#""#]],
682 );
683 }
684
685 #[test]
660 fn completes_in_assoc_item_list() { 686 fn completes_in_assoc_item_list() {
661 check( 687 check(
662 r#" 688 r#"
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 1f6c4069f..b1e6b2b77 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -481,14 +481,14 @@ impl S {
481 ); 481 );
482 check( 482 check(
483 r#" 483 r#"
484mod m { 484#[rustc_builtin_macro]
485 #[rustc_builtin_macro] 485pub macro bench {}
486 pub macro Clone {}
487}
488 486
489fn f() {m::$0} 487fn f() {$0}
490"#, 488"#,
491 expect![[r#""#]], 489 expect![[r#"
490 fn f() fn()
491 "#]],
492 ); 492 );
493 } 493 }
494 494
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 7118183fe..902df46ca 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -24,34 +24,34 @@ use crate::{
24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, 24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
25}; 25};
26 26
27pub(crate) fn render_field<'a>( 27pub(crate) fn render_field(
28 ctx: RenderContext<'a>, 28 ctx: RenderContext<'_>,
29 receiver: Option<hir::Name>, 29 receiver: Option<hir::Name>,
30 field: hir::Field, 30 field: hir::Field,
31 ty: &hir::Type, 31 ty: &hir::Type,
32) -> CompletionItem { 32) -> CompletionItem {
33 Render::new(ctx).render_field(receiver, field, ty) 33 render_field_(ctx, receiver, field, ty)
34} 34}
35 35
36pub(crate) fn render_tuple_field<'a>( 36pub(crate) fn render_tuple_field(
37 ctx: RenderContext<'a>, 37 ctx: RenderContext<'_>,
38 receiver: Option<hir::Name>, 38 receiver: Option<hir::Name>,
39 field: usize, 39 field: usize,
40 ty: &hir::Type, 40 ty: &hir::Type,
41) -> CompletionItem { 41) -> CompletionItem {
42 Render::new(ctx).render_tuple_field(receiver, field, ty) 42 render_tuple_field_(ctx, receiver, field, ty)
43} 43}
44 44
45pub(crate) fn render_resolution<'a>( 45pub(crate) fn render_resolution(
46 ctx: RenderContext<'a>, 46 ctx: RenderContext<'_>,
47 local_name: hir::Name, 47 local_name: hir::Name,
48 resolution: &hir::ScopeDef, 48 resolution: &hir::ScopeDef,
49) -> Option<CompletionItem> { 49) -> Option<CompletionItem> {
50 Render::new(ctx).render_resolution(local_name, None, resolution) 50 render_resolution_(ctx, local_name, None, resolution)
51} 51}
52 52
53pub(crate) fn render_resolution_with_import<'a>( 53pub(crate) fn render_resolution_with_import(
54 ctx: RenderContext<'a>, 54 ctx: RenderContext<'_>,
55 import_edit: ImportEdit, 55 import_edit: ImportEdit,
56) -> Option<CompletionItem> { 56) -> Option<CompletionItem> {
57 let resolution = hir::ScopeDef::from(import_edit.import.original_item); 57 let resolution = hir::ScopeDef::from(import_edit.import.original_item);
@@ -64,12 +64,10 @@ pub(crate) fn render_resolution_with_import<'a>(
64 hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), 64 hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
65 _ => item_name(ctx.db(), import_edit.import.original_item)?, 65 _ => item_name(ctx.db(), import_edit.import.original_item)?,
66 }; 66 };
67 Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( 67 render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| {
68 |mut item| { 68 item.completion_kind = CompletionKind::Magic;
69 item.completion_kind = CompletionKind::Magic; 69 item
70 item 70 })
71 },
72 )
73} 71}
74 72
75/// Interface for data and methods required for items rendering. 73/// Interface for data and methods required for items rendering.
@@ -121,216 +119,188 @@ impl<'a> RenderContext<'a> {
121 } 119 }
122} 120}
123 121
124/// Generic renderer for completion items. 122fn render_field_(
125#[derive(Debug)] 123 ctx: RenderContext<'_>,
126struct Render<'a> { 124 receiver: Option<hir::Name>,
127 ctx: RenderContext<'a>, 125 field: hir::Field,
128} 126 ty: &hir::Type,
129 127) -> CompletionItem {
130impl<'a> Render<'a> { 128 let is_deprecated = ctx.is_deprecated(field);
131 fn new(ctx: RenderContext<'a>) -> Render<'a> { 129 let name = field.name(ctx.db()).to_string();
132 Render { ctx } 130 let mut item = CompletionItem::new(
131 CompletionKind::Reference,
132 ctx.source_range(),
133 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
134 );
135 item.kind(SymbolKind::Field)
136 .detail(ty.display(ctx.db()).to_string())
137 .set_documentation(field.docs(ctx.db()))
138 .set_deprecated(is_deprecated);
139
140 item.set_relevance(CompletionRelevance {
141 type_match: compute_type_match(ctx.completion, ty),
142 exact_name_match: compute_exact_name_match(ctx.completion, &name),
143 ..CompletionRelevance::default()
144 });
145
146 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
147 // FIXME
148 // For now we don't properly calculate the edits for ref match
149 // completions on struct fields, so we've disabled them. See #8058.
133 } 150 }
134 151
135 fn render_field( 152 item.build()
136 &self, 153}
137 receiver: Option<hir::Name>,
138 field: hir::Field,
139 ty: &hir::Type,
140 ) -> CompletionItem {
141 let is_deprecated = self.ctx.is_deprecated(field);
142 let name = field.name(self.ctx.db()).to_string();
143 let mut item = CompletionItem::new(
144 CompletionKind::Reference,
145 self.ctx.source_range(),
146 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
147 );
148 item.kind(SymbolKind::Field)
149 .detail(ty.display(self.ctx.db()).to_string())
150 .set_documentation(field.docs(self.ctx.db()))
151 .set_deprecated(is_deprecated);
152
153 item.set_relevance(CompletionRelevance {
154 type_match: compute_type_match(self.ctx.completion, ty),
155 exact_name_match: compute_exact_name_match(self.ctx.completion, &name),
156 ..CompletionRelevance::default()
157 });
158
159 if let Some(_ref_match) = compute_ref_match(self.ctx.completion, ty) {
160 // FIXME
161 // For now we don't properly calculate the edits for ref match
162 // completions on struct fields, so we've disabled them. See #8058.
163 }
164 154
165 item.build() 155fn render_tuple_field_(
166 } 156 ctx: RenderContext<'_>,
157 receiver: Option<hir::Name>,
158 field: usize,
159 ty: &hir::Type,
160) -> CompletionItem {
161 let mut item = CompletionItem::new(
162 CompletionKind::Reference,
163 ctx.source_range(),
164 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
165 );
167 166
168 fn render_tuple_field( 167 item.kind(SymbolKind::Field).detail(ty.display(ctx.db()).to_string());
169 &self,
170 receiver: Option<hir::Name>,
171 field: usize,
172 ty: &hir::Type,
173 ) -> CompletionItem {
174 let mut item = CompletionItem::new(
175 CompletionKind::Reference,
176 self.ctx.source_range(),
177 receiver
178 .map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
179 );
180 168
181 item.kind(SymbolKind::Field).detail(ty.display(self.ctx.db()).to_string()); 169 item.build()
170}
182 171
183 item.build() 172fn render_resolution_(
184 } 173 ctx: RenderContext<'_>,
174 local_name: hir::Name,
175 import_to_add: Option<ImportEdit>,
176 resolution: &hir::ScopeDef,
177) -> Option<CompletionItem> {
178 let _p = profile::span("render_resolution");
179 use hir::ModuleDef::*;
185 180
186 fn render_resolution( 181 let completion_kind = match resolution {
187 self, 182 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
188 local_name: hir::Name, 183 _ => CompletionKind::Reference,
189 import_to_add: Option<ImportEdit>, 184 };
190 resolution: &hir::ScopeDef,
191 ) -> Option<CompletionItem> {
192 let _p = profile::span("render_resolution");
193 use hir::ModuleDef::*;
194
195 let completion_kind = match resolution {
196 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
197 _ => CompletionKind::Reference,
198 };
199 185
200 let kind = match resolution { 186 let kind = match resolution {
201 hir::ScopeDef::ModuleDef(Function(func)) => { 187 hir::ScopeDef::ModuleDef(Function(func)) => {
202 return render_fn(self.ctx, import_to_add, Some(local_name), *func); 188 return render_fn(ctx, import_to_add, Some(local_name), *func);
203 } 189 }
204 hir::ScopeDef::ModuleDef(Variant(_)) 190 hir::ScopeDef::ModuleDef(Variant(_)) if ctx.completion.is_pat_or_const.is_some() => {
205 if self.ctx.completion.is_pat_or_const.is_some() => 191 CompletionItemKind::SymbolKind(SymbolKind::Variant)
206 { 192 }
207 CompletionItemKind::SymbolKind(SymbolKind::Variant) 193 hir::ScopeDef::ModuleDef(Variant(var)) => {
208 } 194 let item = render_variant(ctx, import_to_add, Some(local_name), *var, None);
209 hir::ScopeDef::ModuleDef(Variant(var)) => { 195 return Some(item);
210 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); 196 }
211 return Some(item); 197 hir::ScopeDef::MacroDef(mac) => {
212 } 198 let item = render_macro(ctx, import_to_add, local_name, *mac);
213 hir::ScopeDef::MacroDef(mac) => { 199 return item;
214 let item = render_macro(self.ctx, import_to_add, local_name, *mac); 200 }
215 return item;
216 }
217 201
218 hir::ScopeDef::ModuleDef(Module(..)) => { 202 hir::ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
219 CompletionItemKind::SymbolKind(SymbolKind::Module) 203 hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
220 } 204 hir::Adt::Struct(_) => SymbolKind::Struct,
221 hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { 205 hir::Adt::Union(_) => SymbolKind::Union,
222 hir::Adt::Struct(_) => SymbolKind::Struct, 206 hir::Adt::Enum(_) => SymbolKind::Enum,
223 hir::Adt::Union(_) => SymbolKind::Union, 207 }),
224 hir::Adt::Enum(_) => SymbolKind::Enum, 208 hir::ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
225 }), 209 hir::ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
226 hir::ScopeDef::ModuleDef(Const(..)) => { 210 hir::ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
227 CompletionItemKind::SymbolKind(SymbolKind::Const) 211 hir::ScopeDef::ModuleDef(TypeAlias(..)) => {
228 } 212 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
229 hir::ScopeDef::ModuleDef(Static(..)) => { 213 }
230 CompletionItemKind::SymbolKind(SymbolKind::Static) 214 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
231 } 215 hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
232 hir::ScopeDef::ModuleDef(Trait(..)) => { 216 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
233 CompletionItemKind::SymbolKind(SymbolKind::Trait) 217 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
234 } 218 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
235 hir::ScopeDef::ModuleDef(TypeAlias(..)) => { 219 }),
236 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) 220 hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
237 } 221 hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
238 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 222 hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => {
239 hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { 223 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
240 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, 224 }
241 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, 225 hir::ScopeDef::Unknown => {
242 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, 226 let mut item = CompletionItem::new(
243 }), 227 CompletionKind::Reference,
244 hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), 228 ctx.source_range(),
245 hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), 229 local_name.to_string(),
246 hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => { 230 );
247 CompletionItemKind::SymbolKind(SymbolKind::SelfParam) 231 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
248 } 232 return Some(item.build());
249 hir::ScopeDef::Unknown => { 233 }
250 let mut item = CompletionItem::new( 234 };
251 CompletionKind::Reference,
252 self.ctx.source_range(),
253 local_name.to_string(),
254 );
255 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
256 return Some(item.build());
257 }
258 };
259 235
260 let local_name = local_name.to_string(); 236 let local_name = local_name.to_string();
261 let mut item = 237 let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
262 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); 238 if let hir::ScopeDef::Local(local) = resolution {
263 if let hir::ScopeDef::Local(local) = resolution { 239 let ty = local.ty(ctx.db());
264 let ty = local.ty(self.ctx.db()); 240 if !ty.is_unknown() {
265 if !ty.is_unknown() { 241 item.detail(ty.display(ctx.db()).to_string());
266 item.detail(ty.display(self.ctx.db()).to_string()); 242 }
267 }
268 243
269 item.set_relevance(CompletionRelevance { 244 item.set_relevance(CompletionRelevance {
270 type_match: compute_type_match(self.ctx.completion, &ty), 245 type_match: compute_type_match(ctx.completion, &ty),
271 exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name), 246 exact_name_match: compute_exact_name_match(ctx.completion, &local_name),
272 is_local: true, 247 is_local: true,
273 ..CompletionRelevance::default() 248 ..CompletionRelevance::default()
274 }); 249 });
275 250
276 if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) { 251 if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) {
277 item.ref_match(ref_match); 252 item.ref_match(ref_match);
278 } 253 }
279 }; 254 };
280 255
281 // Add `<>` for generic types 256 // Add `<>` for generic types
282 if matches!( 257 if matches!(
283 self.ctx.completion.path_context, 258 ctx.completion.path_context,
284 Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. }) 259 Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
285 ) && self.ctx.completion.config.add_call_parenthesis 260 ) && ctx.completion.config.add_call_parenthesis
286 { 261 {
287 if let Some(cap) = self.ctx.snippet_cap() { 262 if let Some(cap) = ctx.snippet_cap() {
288 let has_non_default_type_params = match resolution { 263 let has_non_default_type_params = match resolution {
289 hir::ScopeDef::ModuleDef(Adt(it)) => { 264 hir::ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()),
290 it.has_non_default_type_params(self.ctx.db()) 265 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()),
291 } 266 _ => false,
292 hir::ScopeDef::ModuleDef(TypeAlias(it)) => { 267 };
293 it.has_non_default_type_params(self.ctx.db()) 268 if has_non_default_type_params {
294 } 269 cov_mark::hit!(inserts_angle_brackets_for_generics);
295 _ => false, 270 item.lookup_by(local_name.clone())
296 }; 271 .label(format!("{}<…>", local_name))
297 if has_non_default_type_params { 272 .insert_snippet(cap, format!("{}<$0>", local_name));
298 cov_mark::hit!(inserts_angle_brackets_for_generics);
299 item.lookup_by(local_name.clone())
300 .label(format!("{}<…>", local_name))
301 .insert_snippet(cap, format!("{}<$0>", local_name));
302 }
303 } 273 }
304 } 274 }
305 item.kind(kind)
306 .add_import(import_to_add)
307 .set_documentation(self.docs(resolution))
308 .set_deprecated(self.is_deprecated(resolution));
309 Some(item.build())
310 } 275 }
276 item.kind(kind)
277 .add_import(import_to_add)
278 .set_documentation(scope_def_docs(ctx.db(), resolution))
279 .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
280 Some(item.build())
281}
311 282
312 fn docs(&self, resolution: &hir::ScopeDef) -> Option<hir::Documentation> { 283fn scope_def_docs(db: &RootDatabase, resolution: &hir::ScopeDef) -> Option<hir::Documentation> {
313 use hir::ModuleDef::*; 284 use hir::ModuleDef::*;
314 match resolution { 285 match resolution {
315 hir::ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()), 286 hir::ScopeDef::ModuleDef(Module(it)) => it.docs(db),
316 hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()), 287 hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
317 hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()), 288 hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
318 hir::ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()), 289 hir::ScopeDef::ModuleDef(Const(it)) => it.docs(db),
319 hir::ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()), 290 hir::ScopeDef::ModuleDef(Static(it)) => it.docs(db),
320 hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()), 291 hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
321 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()), 292 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
322 _ => None, 293 _ => None,
323 }
324 } 294 }
295}
325 296
326 fn is_deprecated(&self, resolution: &hir::ScopeDef) -> bool { 297fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: &hir::ScopeDef) -> bool {
327 match resolution { 298 match resolution {
328 hir::ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), 299 hir::ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(*it),
329 hir::ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), 300 hir::ScopeDef::MacroDef(it) => ctx.is_deprecated(*it),
330 hir::ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), 301 hir::ScopeDef::GenericParam(it) => ctx.is_deprecated(*it),
331 hir::ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), 302 hir::ScopeDef::AdtSelfType(it) => ctx.is_deprecated(*it),
332 _ => false, 303 _ => false,
333 }
334 } 304 }
335} 305}
336 306