aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs7
-rw-r--r--crates/hir/src/semantics/source_to_def.rs106
-rw-r--r--crates/ide_completion/src/completions/pattern.rs24
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs11
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs50
-rw-r--r--editors/code/src/ctx.ts1
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#"
108macro_rules! m { ($e:expr) => { $e } }
109enum E { X }
110
111#[rustc_builtin_macro]
112macro Clone {}
113
114fn 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]
462pub macro Clone {}
463
464fn f() {$0}
465"#,
466 expect![[r#"
467 fn f() fn()
468 "#]],
469 );
470 check(
471 r#"
472#[rustc_builtin_macro]
473pub macro Clone {}
474
475struct S;
476impl S {
477 $0
478}
479"#,
480 expect![[r#""#]],
481 );
482 check(
483 r#"
484mod m {
485 #[rustc_builtin_macro]
486 pub macro Clone {}
487}
488
489fn 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);