diff options
-rw-r--r-- | crates/hir/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/hir/src/semantics/source_to_def.rs | 106 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/pattern.rs | 24 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/qualified_path.rs | 11 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 50 | ||||
-rw-r--r-- | editors/code/src/ctx.ts | 1 |
6 files changed, 145 insertions, 54 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 589641760..dba46df04 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -1351,6 +1351,13 @@ impl MacroDef { | |||
1351 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, | 1351 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, |
1352 | } | 1352 | } |
1353 | } | 1353 | } |
1354 | |||
1355 | pub fn is_fn_like(&self) -> bool { | ||
1356 | match self.kind() { | ||
1357 | MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true, | ||
1358 | MacroKind::Attr | MacroKind::Derive => false, | ||
1359 | } | ||
1360 | } | ||
1354 | } | 1361 | } |
1355 | 1362 | ||
1356 | /// Invariant: `inner.as_assoc_item(db).is_some()` | 1363 | /// Invariant: `inner.as_assoc_item(db).is_some()` |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 22e196196..e8c2ed48e 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -211,62 +211,68 @@ impl SourceToDefCtx<'_, '_> { | |||
211 | 211 | ||
212 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { | 212 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { |
213 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { | 213 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { |
214 | let res: ChildContainer = match_ast! { | 214 | if let Some(res) = self.container_to_def(container) { |
215 | match (container.value) { | 215 | return Some(res); |
216 | ast::Module(it) => { | 216 | } |
217 | let def = self.module_to_def(container.with_value(it))?; | ||
218 | def.into() | ||
219 | }, | ||
220 | ast::Trait(it) => { | ||
221 | let def = self.trait_to_def(container.with_value(it))?; | ||
222 | def.into() | ||
223 | }, | ||
224 | ast::Impl(it) => { | ||
225 | let def = self.impl_to_def(container.with_value(it))?; | ||
226 | def.into() | ||
227 | }, | ||
228 | ast::Fn(it) => { | ||
229 | let def = self.fn_to_def(container.with_value(it))?; | ||
230 | DefWithBodyId::from(def).into() | ||
231 | }, | ||
232 | ast::Struct(it) => { | ||
233 | let def = self.struct_to_def(container.with_value(it))?; | ||
234 | VariantId::from(def).into() | ||
235 | }, | ||
236 | ast::Enum(it) => { | ||
237 | let def = self.enum_to_def(container.with_value(it))?; | ||
238 | def.into() | ||
239 | }, | ||
240 | ast::Union(it) => { | ||
241 | let def = self.union_to_def(container.with_value(it))?; | ||
242 | VariantId::from(def).into() | ||
243 | }, | ||
244 | ast::Static(it) => { | ||
245 | let def = self.static_to_def(container.with_value(it))?; | ||
246 | DefWithBodyId::from(def).into() | ||
247 | }, | ||
248 | ast::Const(it) => { | ||
249 | let def = self.const_to_def(container.with_value(it))?; | ||
250 | DefWithBodyId::from(def).into() | ||
251 | }, | ||
252 | ast::TypeAlias(it) => { | ||
253 | let def = self.type_alias_to_def(container.with_value(it))?; | ||
254 | def.into() | ||
255 | }, | ||
256 | ast::Variant(it) => { | ||
257 | let def = self.enum_variant_to_def(container.with_value(it))?; | ||
258 | VariantId::from(def).into() | ||
259 | }, | ||
260 | _ => continue, | ||
261 | } | ||
262 | }; | ||
263 | return Some(res); | ||
264 | } | 217 | } |
265 | 218 | ||
266 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; | 219 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; |
267 | Some(def.into()) | 220 | Some(def.into()) |
268 | } | 221 | } |
269 | 222 | ||
223 | fn container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer> { | ||
224 | let cont = match_ast! { | ||
225 | match (container.value) { | ||
226 | ast::Module(it) => { | ||
227 | let def = self.module_to_def(container.with_value(it))?; | ||
228 | def.into() | ||
229 | }, | ||
230 | ast::Trait(it) => { | ||
231 | let def = self.trait_to_def(container.with_value(it))?; | ||
232 | def.into() | ||
233 | }, | ||
234 | ast::Impl(it) => { | ||
235 | let def = self.impl_to_def(container.with_value(it))?; | ||
236 | def.into() | ||
237 | }, | ||
238 | ast::Fn(it) => { | ||
239 | let def = self.fn_to_def(container.with_value(it))?; | ||
240 | DefWithBodyId::from(def).into() | ||
241 | }, | ||
242 | ast::Struct(it) => { | ||
243 | let def = self.struct_to_def(container.with_value(it))?; | ||
244 | VariantId::from(def).into() | ||
245 | }, | ||
246 | ast::Enum(it) => { | ||
247 | let def = self.enum_to_def(container.with_value(it))?; | ||
248 | def.into() | ||
249 | }, | ||
250 | ast::Union(it) => { | ||
251 | let def = self.union_to_def(container.with_value(it))?; | ||
252 | VariantId::from(def).into() | ||
253 | }, | ||
254 | ast::Static(it) => { | ||
255 | let def = self.static_to_def(container.with_value(it))?; | ||
256 | DefWithBodyId::from(def).into() | ||
257 | }, | ||
258 | ast::Const(it) => { | ||
259 | let def = self.const_to_def(container.with_value(it))?; | ||
260 | DefWithBodyId::from(def).into() | ||
261 | }, | ||
262 | ast::TypeAlias(it) => { | ||
263 | let def = self.type_alias_to_def(container.with_value(it))?; | ||
264 | def.into() | ||
265 | }, | ||
266 | ast::Variant(it) => { | ||
267 | let def = self.enum_variant_to_def(container.with_value(it))?; | ||
268 | VariantId::from(def).into() | ||
269 | }, | ||
270 | _ => return None, | ||
271 | } | ||
272 | }; | ||
273 | Some(cont) | ||
274 | } | ||
275 | |||
270 | fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { | 276 | fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { |
271 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { | 277 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { |
272 | let res: GenericDefId = match_ast! { | 278 | let res: GenericDefId = match_ast! { |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 8a728c67e..1daa8595a 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -39,7 +39,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
39 | | hir::ModuleDef::Module(..) => refutable, | 39 | | hir::ModuleDef::Module(..) => refutable, |
40 | _ => false, | 40 | _ => false, |
41 | }, | 41 | }, |
42 | hir::ScopeDef::MacroDef(_) => true, | 42 | hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { | 43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { |
44 | Some(hir::Adt::Struct(strukt)) => { | 44 | Some(hir::Adt::Struct(strukt)) => { |
45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); | 45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); |
@@ -102,6 +102,28 @@ fn foo() { | |||
102 | } | 102 | } |
103 | 103 | ||
104 | #[test] | 104 | #[test] |
105 | fn does_not_complete_non_fn_macros() { | ||
106 | check( | ||
107 | r#" | ||
108 | macro_rules! m { ($e:expr) => { $e } } | ||
109 | enum E { X } | ||
110 | |||
111 | #[rustc_builtin_macro] | ||
112 | macro Clone {} | ||
113 | |||
114 | fn foo() { | ||
115 | match E::X { $0 } | ||
116 | } | ||
117 | "#, | ||
118 | expect![[r#" | ||
119 | ev E::X () | ||
120 | en E | ||
121 | ma m!(…) macro_rules! m | ||
122 | "#]], | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
105 | fn completes_in_simple_macro_call() { | 127 | fn completes_in_simple_macro_call() { |
106 | check( | 128 | check( |
107 | r#" | 129 | r#" |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index a5cba5938..0b0a81410 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -26,7 +26,9 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
26 | let module_scope = module.scope(ctx.db, context_module); | 26 | let module_scope = module.scope(ctx.db, context_module); |
27 | for (name, def) in module_scope { | 27 | for (name, def) in module_scope { |
28 | if let hir::ScopeDef::MacroDef(macro_def) = def { | 28 | if let hir::ScopeDef::MacroDef(macro_def) = def { |
29 | acc.add_macro(ctx, Some(name.clone()), macro_def); | 29 | if macro_def.is_fn_like() { |
30 | acc.add_macro(ctx, Some(name.clone()), macro_def); | ||
31 | } | ||
30 | } | 32 | } |
31 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { | 33 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { |
32 | acc.add_resolution(ctx, name, &def); | 34 | acc.add_resolution(ctx, name, &def); |
@@ -58,6 +60,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
58 | } | 60 | } |
59 | } | 61 | } |
60 | 62 | ||
63 | if let hir::ScopeDef::MacroDef(macro_def) = def { | ||
64 | if !macro_def.is_fn_like() { | ||
65 | // Don't suggest attribute macros and derives. | ||
66 | continue; | ||
67 | } | ||
68 | } | ||
69 | |||
61 | acc.add_resolution(ctx, name, &def); | 70 | acc.add_resolution(ctx, name, &def); |
62 | } | 71 | } |
63 | } | 72 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 2105bb428..1f6c4069f 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -13,7 +13,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
13 | // only show macros in {Assoc}ItemList | 13 | // only show macros in {Assoc}ItemList |
14 | ctx.scope.process_all_names(&mut |name, res| { | 14 | ctx.scope.process_all_names(&mut |name, res| { |
15 | if let hir::ScopeDef::MacroDef(mac) = res { | 15 | if let hir::ScopeDef::MacroDef(mac) = res { |
16 | acc.add_macro(ctx, Some(name.clone()), mac); | 16 | if mac.is_fn_like() { |
17 | acc.add_macro(ctx, Some(name.clone()), mac); | ||
18 | } | ||
17 | } | 19 | } |
18 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { | 20 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { |
19 | acc.add_resolution(ctx, name, &res); | 21 | acc.add_resolution(ctx, name, &res); |
@@ -46,7 +48,13 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
46 | cov_mark::hit!(skip_lifetime_completion); | 48 | cov_mark::hit!(skip_lifetime_completion); |
47 | return; | 49 | return; |
48 | } | 50 | } |
49 | acc.add_resolution(ctx, name, &res); | 51 | let add_resolution = match res { |
52 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), | ||
53 | _ => true, | ||
54 | }; | ||
55 | if add_resolution { | ||
56 | acc.add_resolution(ctx, name, &res); | ||
57 | } | ||
50 | }); | 58 | }); |
51 | } | 59 | } |
52 | 60 | ||
@@ -447,6 +455,44 @@ mod macros { | |||
447 | } | 455 | } |
448 | 456 | ||
449 | #[test] | 457 | #[test] |
458 | fn does_not_complete_non_fn_macros() { | ||
459 | check( | ||
460 | r#" | ||
461 | #[rustc_builtin_macro] | ||
462 | pub macro Clone {} | ||
463 | |||
464 | fn f() {$0} | ||
465 | "#, | ||
466 | expect![[r#" | ||
467 | fn f() fn() | ||
468 | "#]], | ||
469 | ); | ||
470 | check( | ||
471 | r#" | ||
472 | #[rustc_builtin_macro] | ||
473 | pub macro Clone {} | ||
474 | |||
475 | struct S; | ||
476 | impl S { | ||
477 | $0 | ||
478 | } | ||
479 | "#, | ||
480 | expect![[r#""#]], | ||
481 | ); | ||
482 | check( | ||
483 | r#" | ||
484 | mod m { | ||
485 | #[rustc_builtin_macro] | ||
486 | pub macro Clone {} | ||
487 | } | ||
488 | |||
489 | fn f() {m::$0} | ||
490 | "#, | ||
491 | expect![[r#""#]], | ||
492 | ); | ||
493 | } | ||
494 | |||
495 | #[test] | ||
450 | fn completes_std_prelude_if_core_is_defined() { | 496 | fn completes_std_prelude_if_core_is_defined() { |
451 | check( | 497 | check( |
452 | r#" | 498 | r#" |
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index cf67dd8cf..2ffd3be6f 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts | |||
@@ -39,6 +39,7 @@ export class Ctx { | |||
39 | extCtx.subscriptions.push(statusBar); | 39 | extCtx.subscriptions.push(statusBar); |
40 | statusBar.text = "rust-analyzer"; | 40 | statusBar.text = "rust-analyzer"; |
41 | statusBar.tooltip = "ready"; | 41 | statusBar.tooltip = "ready"; |
42 | statusBar.command = "rust-analyzer.analyzerStatus"; | ||
42 | statusBar.show(); | 43 | statusBar.show(); |
43 | 44 | ||
44 | const res = new Ctx(config, extCtx, client, serverPath, statusBar); | 45 | const res = new Ctx(config, extCtx, client, serverPath, statusBar); |