aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs19
-rw-r--r--crates/hir/src/semantics.rs3
-rw-r--r--crates/hir/src/semantics/source_to_def.rs106
-rw-r--r--crates/ide_completion/src/completions.rs51
-rw-r--r--crates/ide_completion/src/completions/attribute.rs4
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs3
-rw-r--r--crates/ide_completion/src/completions/pattern.rs24
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs41
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs76
-rw-r--r--crates/ide_completion/src/context.rs42
-rw-r--r--crates/ide_completion/src/render.rs15
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs18
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs15
-rw-r--r--crates/syntax/src/ast/node_ext.rs5
-rw-r--r--editors/code/src/ctx.ts1
15 files changed, 306 insertions, 117 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index c2b68a853..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()`
@@ -2496,6 +2503,18 @@ impl ScopeDef {
2496 2503
2497 items 2504 items
2498 } 2505 }
2506
2507 pub fn is_value_def(&self) -> bool {
2508 matches!(
2509 self,
2510 ScopeDef::ModuleDef(ModuleDef::Function(_))
2511 | ScopeDef::ModuleDef(ModuleDef::Variant(_))
2512 | ScopeDef::ModuleDef(ModuleDef::Const(_))
2513 | ScopeDef::ModuleDef(ModuleDef::Static(_))
2514 | ScopeDef::GenericParam(GenericParam::ConstParam(_))
2515 | ScopeDef::Local(_)
2516 )
2517 }
2499} 2518}
2500 2519
2501impl From<ItemInNs> for ScopeDef { 2520impl From<ItemInNs> for ScopeDef {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2d08a7704..827e23e2b 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -35,8 +35,9 @@ pub enum PathResolution {
35 Def(ModuleDef), 35 Def(ModuleDef),
36 /// A local binding (only value namespace) 36 /// A local binding (only value namespace)
37 Local(Local), 37 Local(Local),
38 /// A generic parameter 38 /// A type parameter
39 TypeParam(TypeParam), 39 TypeParam(TypeParam),
40 /// A const parameter
40 ConstParam(ConstParam), 41 ConstParam(ConstParam),
41 SelfType(Impl), 42 SelfType(Impl),
42 Macro(MacroDef), 43 Macro(MacroDef),
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.rs b/crates/ide_completion/src/completions.rs
index 7a4d71e91..fbd499900 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -56,10 +56,16 @@ impl Builder {
56} 56}
57 57
58impl Completions { 58impl Completions {
59 pub(crate) fn add(&mut self, item: CompletionItem) { 59 fn add(&mut self, item: CompletionItem) {
60 self.buf.push(item) 60 self.buf.push(item)
61 } 61 }
62 62
63 fn add_opt(&mut self, item: Option<CompletionItem>) {
64 if let Some(item) = item {
65 self.buf.push(item)
66 }
67 }
68
63 pub(crate) fn add_all<I>(&mut self, items: I) 69 pub(crate) fn add_all<I>(&mut self, items: I)
64 where 70 where
65 I: IntoIterator, 71 I: IntoIterator,
@@ -103,9 +109,10 @@ impl Completions {
103 local_name: hir::Name, 109 local_name: hir::Name,
104 resolution: &hir::ScopeDef, 110 resolution: &hir::ScopeDef,
105 ) { 111 ) {
106 if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { 112 if ctx.expects_type() && resolution.is_value_def() {
107 self.add(item); 113 return;
108 } 114 }
115 self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution));
109 } 116 }
110 117
111 pub(crate) fn add_macro( 118 pub(crate) fn add_macro(
@@ -118,9 +125,7 @@ impl Completions {
118 Some(it) => it, 125 Some(it) => it,
119 None => return, 126 None => return,
120 }; 127 };
121 if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) { 128 self.add_opt(render_macro(RenderContext::new(ctx), None, name, macro_));
122 self.add(item);
123 }
124 } 129 }
125 130
126 pub(crate) fn add_function( 131 pub(crate) fn add_function(
@@ -129,9 +134,10 @@ impl Completions {
129 func: hir::Function, 134 func: hir::Function,
130 local_name: Option<hir::Name>, 135 local_name: Option<hir::Name>,
131 ) { 136 ) {
132 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { 137 if ctx.expects_type() {
133 self.add(item) 138 return;
134 } 139 }
140 self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func));
135 } 141 }
136 142
137 pub(crate) fn add_method( 143 pub(crate) fn add_method(
@@ -141,10 +147,7 @@ impl Completions {
141 receiver: Option<hir::Name>, 147 receiver: Option<hir::Name>,
142 local_name: Option<hir::Name>, 148 local_name: Option<hir::Name>,
143 ) { 149 ) {
144 if let Some(item) = render_method(RenderContext::new(ctx), None, receiver, local_name, func) 150 self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
145 {
146 self.add(item)
147 }
148 } 151 }
149 152
150 pub(crate) fn add_variant_pat( 153 pub(crate) fn add_variant_pat(
@@ -153,9 +156,7 @@ impl Completions {
153 variant: hir::Variant, 156 variant: hir::Variant,
154 local_name: Option<hir::Name>, 157 local_name: Option<hir::Name>,
155 ) { 158 ) {
156 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name, None) { 159 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None));
157 self.add(item);
158 }
159 } 160 }
160 161
161 pub(crate) fn add_qualified_variant_pat( 162 pub(crate) fn add_qualified_variant_pat(
@@ -164,9 +165,7 @@ impl Completions {
164 variant: hir::Variant, 165 variant: hir::Variant,
165 path: hir::ModPath, 166 path: hir::ModPath,
166 ) { 167 ) {
167 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) { 168 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)));
168 self.add(item);
169 }
170 } 169 }
171 170
172 pub(crate) fn add_struct_pat( 171 pub(crate) fn add_struct_pat(
@@ -175,21 +174,18 @@ impl Completions {
175 strukt: hir::Struct, 174 strukt: hir::Struct,
176 local_name: Option<hir::Name>, 175 local_name: Option<hir::Name>,
177 ) { 176 ) {
178 if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) { 177 self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name));
179 self.add(item);
180 }
181 } 178 }
182 179
183 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { 180 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
184 if let Some(item) = render_const(RenderContext::new(ctx), constant) { 181 if ctx.expects_type() {
185 self.add(item); 182 return;
186 } 183 }
184 self.add_opt(render_const(RenderContext::new(ctx), constant));
187 } 185 }
188 186
189 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { 187 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
190 if let Some(item) = render_type_alias(RenderContext::new(ctx), type_alias) { 188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias));
191 self.add(item)
192 }
193 } 189 }
194 190
195 pub(crate) fn add_qualified_enum_variant( 191 pub(crate) fn add_qualified_enum_variant(
@@ -208,6 +204,9 @@ impl Completions {
208 variant: hir::Variant, 204 variant: hir::Variant,
209 local_name: Option<hir::Name>, 205 local_name: Option<hir::Name>,
210 ) { 206 ) {
207 if ctx.expects_type() {
208 return;
209 }
211 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); 210 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None);
212 self.add(item); 211 self.add(item);
213 } 212 }
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index d3392100d..7f76e357e 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -69,7 +69,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
69 } 69 }
70 70
71 if is_inner || !attr_completion.prefer_inner { 71 if is_inner || !attr_completion.prefer_inner {
72 acc.add(item.build()); 72 item.add_to(acc);
73 } 73 }
74 }; 74 };
75 75
@@ -96,7 +96,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
96 if let Some(docs) = mac.docs(ctx.sema.db) { 96 if let Some(docs) = mac.docs(ctx.sema.db) {
97 item.documentation(docs); 97 item.documentation(docs);
98 } 98 }
99 acc.add(item.build()); 99 item.add_to(acc);
100 } 100 }
101 } 101 }
102 }); 102 });
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 7bf47bf75..c010cbbca 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -90,7 +90,6 @@
90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
91//! capability enabled. 91//! capability enabled.
92 92
93use hir::ModPath;
94use ide_db::helpers::{ 93use ide_db::helpers::{
95 import_assets::{ImportAssets, ImportCandidate}, 94 import_assets::{ImportAssets, ImportCandidate},
96 insert_use::ImportScope, 95 insert_use::ImportScope,
@@ -208,7 +207,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
208} 207}
209 208
210fn compute_fuzzy_completion_order_key( 209fn compute_fuzzy_completion_order_key(
211 proposed_mod_path: &ModPath, 210 proposed_mod_path: &hir::ModPath,
212 user_input_lowercased: &str, 211 user_input_lowercased: &str,
213) -> usize { 212) -> usize {
214 cov_mark::hit!(certain_fuzzy_order_test); 213 cov_mark::hit!(certain_fuzzy_order_test);
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 d58745fb4..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 }
@@ -199,6 +208,36 @@ mod tests {
199 } 208 }
200 209
201 #[test] 210 #[test]
211 fn dont_complete_values_in_type_pos() {
212 check(
213 r#"
214const FOO: () = ();
215static BAR: () = ();
216struct Baz;
217fn foo() {
218 let _: self::$0;
219}
220"#,
221 expect![[r#"
222 st Baz
223 "#]],
224 );
225 }
226
227 #[test]
228 fn dont_complete_enum_variants_in_type_pos() {
229 check(
230 r#"
231enum Foo { Bar }
232fn foo() {
233 let _: Foo::$0;
234}
235"#,
236 expect![[r#""#]],
237 );
238 }
239
240 #[test]
202 fn dont_complete_current_use_in_braces_with_glob() { 241 fn dont_complete_current_use_in_braces_with_glob() {
203 check( 242 check(
204 r#" 243 r#"
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 8b22933e0..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
@@ -69,6 +77,28 @@ mod tests {
69 } 77 }
70 78
71 #[test] 79 #[test]
80 fn dont_complete_values_in_type_pos() {
81 check(
82 r#"
83const FOO: () = ();
84static BAR: () = ();
85enum Foo {
86 Bar
87}
88struct Baz;
89fn foo() {
90 let local = ();
91 let _: $0;
92}
93"#,
94 expect![[r#"
95 en Foo
96 st Baz
97 "#]],
98 );
99 }
100
101 #[test]
72 fn only_completes_modules_in_import() { 102 fn only_completes_modules_in_import() {
73 cov_mark::check!(only_completes_modules_in_import); 103 cov_mark::check!(only_completes_modules_in_import);
74 check( 104 check(
@@ -339,7 +369,6 @@ fn x() -> $0
339"#, 369"#,
340 expect![[r#" 370 expect![[r#"
341 st Foo 371 st Foo
342 fn x() fn()
343 "#]], 372 "#]],
344 ); 373 );
345 } 374 }
@@ -391,7 +420,6 @@ pub mod prelude {
391} 420}
392"#, 421"#,
393 expect![[r#" 422 expect![[r#"
394 fn foo() fn()
395 md std 423 md std
396 st Option 424 st Option
397 "#]], 425 "#]],
@@ -427,6 +455,44 @@ mod macros {
427 } 455 }
428 456
429 #[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]
430 fn completes_std_prelude_if_core_is_defined() { 496 fn completes_std_prelude_if_core_is_defined() {
431 check( 497 check(
432 r#" 498 r#"
@@ -448,7 +514,6 @@ pub mod prelude {
448} 514}
449"#, 515"#,
450 expect![[r#" 516 expect![[r#"
451 fn foo() fn()
452 md std 517 md std
453 md core 518 md core
454 st String 519 st String
@@ -509,7 +574,6 @@ macro_rules! foo { () => {} }
509fn main() { let x: $0 } 574fn main() { let x: $0 }
510"#, 575"#,
511 expect![[r#" 576 expect![[r#"
512 fn main() fn()
513 ma foo!(…) macro_rules! foo 577 ma foo!(…) macro_rules! foo
514 "#]], 578 "#]],
515 ); 579 );
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 6177caa12..2c2a4aa6b 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -30,19 +30,24 @@ pub(crate) enum PatternRefutability {
30} 30}
31 31
32#[derive(Debug)] 32#[derive(Debug)]
33pub(super) enum PathKind {
34 Expr,
35 Type,
36}
37
38#[derive(Debug)]
33pub(crate) struct PathCompletionContext { 39pub(crate) struct PathCompletionContext {
34 /// If this is a call with () already there 40 /// If this is a call with () already there
35 call_kind: Option<CallKind>, 41 call_kind: Option<CallKind>,
36 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. 42 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
37 pub(super) is_trivial_path: bool, 43 pub(super) is_trivial_path: bool,
38 /// If not a trivial path, the prefix (qualifier). 44 /// If not a trivial path, the prefix (qualifier).
39 pub(super) path_qual: Option<ast::Path>, 45 pub(super) qualifier: Option<ast::Path>,
40 pub(super) is_path_type: bool, 46 pub(super) kind: Option<PathKind>,
47 /// Whether the path segment has type args or not.
41 pub(super) has_type_args: bool, 48 pub(super) has_type_args: bool,
42 /// `true` if we are a statement or a last expr in the block. 49 /// `true` if we are a statement or a last expr in the block.
43 pub(super) can_be_stmt: bool, 50 pub(super) can_be_stmt: bool,
44 /// `true` if we expect an expression at the cursor position.
45 pub(super) is_expr: bool,
46 pub(super) in_loop_body: bool, 51 pub(super) in_loop_body: bool,
47} 52}
48 53
@@ -308,7 +313,11 @@ impl<'a> CompletionContext<'a> {
308 } 313 }
309 314
310 pub(crate) fn expects_expression(&self) -> bool { 315 pub(crate) fn expects_expression(&self) -> bool {
311 self.path_context.as_ref().map_or(false, |it| it.is_expr) 316 matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Expr), .. }))
317 }
318
319 pub(crate) fn expects_type(&self) -> bool {
320 matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Type), .. }))
312 } 321 }
313 322
314 pub(crate) fn path_call_kind(&self) -> Option<CallKind> { 323 pub(crate) fn path_call_kind(&self) -> Option<CallKind> {
@@ -316,11 +325,11 @@ impl<'a> CompletionContext<'a> {
316 } 325 }
317 326
318 pub(crate) fn is_trivial_path(&self) -> bool { 327 pub(crate) fn is_trivial_path(&self) -> bool {
319 self.path_context.as_ref().map_or(false, |it| it.is_trivial_path) 328 matches!(self.path_context, Some(PathCompletionContext { is_trivial_path: true, .. }))
320 } 329 }
321 330
322 pub(crate) fn path_qual(&self) -> Option<&ast::Path> { 331 pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
323 self.path_context.as_ref().and_then(|it| it.path_qual.as_ref()) 332 self.path_context.as_ref().and_then(|it| it.qualifier.as_ref())
324 } 333 }
325 334
326 fn fill_impl_def(&mut self) { 335 fn fill_impl_def(&mut self) {
@@ -573,12 +582,11 @@ impl<'a> CompletionContext<'a> {
573 let path_ctx = self.path_context.get_or_insert(PathCompletionContext { 582 let path_ctx = self.path_context.get_or_insert(PathCompletionContext {
574 call_kind: None, 583 call_kind: None,
575 is_trivial_path: false, 584 is_trivial_path: false,
576 path_qual: None, 585 qualifier: None,
577 has_type_args: false, 586 has_type_args: false,
578 is_path_type: false,
579 can_be_stmt: false, 587 can_be_stmt: false,
580 is_expr: false,
581 in_loop_body: false, 588 in_loop_body: false,
589 kind: None,
582 }); 590 });
583 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); 591 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
584 let path = segment.parent_path(); 592 let path = segment.parent_path();
@@ -593,11 +601,20 @@ impl<'a> CompletionContext<'a> {
593 } 601 }
594 }; 602 };
595 } 603 }
596 path_ctx.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 604
605 if let Some(parent) = path.syntax().parent() {
606 path_ctx.kind = match_ast! {
607 match parent {
608 ast::PathType(_it) => Some(PathKind::Type),
609 ast::PathExpr(_it) => Some(PathKind::Expr),
610 _ => None,
611 }
612 };
613 }
597 path_ctx.has_type_args = segment.generic_arg_list().is_some(); 614 path_ctx.has_type_args = segment.generic_arg_list().is_some();
598 615
599 if let Some(path) = path_or_use_tree_qualifier(&path) { 616 if let Some(path) = path_or_use_tree_qualifier(&path) {
600 path_ctx.path_qual = path 617 path_ctx.qualifier = path
601 .segment() 618 .segment()
602 .and_then(|it| { 619 .and_then(|it| {
603 find_node_with_range::<ast::PathSegment>( 620 find_node_with_range::<ast::PathSegment>(
@@ -635,7 +652,6 @@ impl<'a> CompletionContext<'a> {
635 None 652 None
636 }) 653 })
637 .unwrap_or(false); 654 .unwrap_or(false);
638 path_ctx.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
639 } 655 }
640 } 656 }
641} 657}
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 750694432..7118183fe 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -18,6 +18,7 @@ use ide_db::{
18use syntax::TextRange; 18use syntax::TextRange;
19 19
20use crate::{ 20use crate::{
21 context::{PathCompletionContext, PathKind},
21 item::{CompletionRelevanceTypeMatch, ImportEdit}, 22 item::{CompletionRelevanceTypeMatch, ImportEdit},
22 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, 23 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
23 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, 24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
@@ -54,6 +55,9 @@ pub(crate) fn render_resolution_with_import<'a>(
54 import_edit: ImportEdit, 55 import_edit: ImportEdit,
55) -> Option<CompletionItem> { 56) -> Option<CompletionItem> {
56 let resolution = hir::ScopeDef::from(import_edit.import.original_item); 57 let resolution = hir::ScopeDef::from(import_edit.import.original_item);
58 if ctx.completion.expects_type() && resolution.is_value_def() {
59 return None;
60 }
57 let local_name = match resolution { 61 let local_name = match resolution {
58 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), 62 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
59 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, 63 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
@@ -275,13 +279,10 @@ impl<'a> Render<'a> {
275 }; 279 };
276 280
277 // Add `<>` for generic types 281 // Add `<>` for generic types
278 if self 282 if matches!(
279 .ctx 283 self.ctx.completion.path_context,
280 .completion 284 Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
281 .path_context 285 ) && self.ctx.completion.config.add_call_parenthesis
282 .as_ref()
283 .map_or(false, |it| it.is_path_type && !it.has_type_args)
284 && self.ctx.completion.config.add_call_parenthesis
285 { 286 {
286 if let Some(cap) = self.ctx.snippet_cap() { 287 if let Some(cap) = self.ctx.snippet_cap() {
287 let has_non_default_type_params = match resolution { 288 let has_non_default_type_params = match resolution {
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index aa61c5bcb..10bbafe77 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -120,15 +120,19 @@ impl ImportScope {
120 if eq_visibility(prev_vis, curr_vis.clone()) && eq_attrs(prev_attrs, curr_attrs.clone()) 120 if eq_visibility(prev_vis, curr_vis.clone()) && eq_attrs(prev_attrs, curr_attrs.clone())
121 { 121 {
122 if let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) { 122 if let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) {
123 if let Some(_) = common_prefix(&prev_path, &curr_path) { 123 if let Some((prev_prefix, _)) = common_prefix(&prev_path, &curr_path) {
124 if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() { 124 if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() {
125 // Same prefix but no use tree lists so this has to be of item style. 125 let prefix_c = prev_prefix.qualifiers().count();
126 break ImportGranularityGuess::Item; // this overwrites CrateOrModule, technically the file doesn't adhere to anything here. 126 let curr_c = curr_path.qualifiers().count() - prefix_c;
127 } else { 127 let prev_c = prev_path.qualifiers().count() - prefix_c;
128 // Same prefix with item tree lists, has to be module style as it 128 if curr_c <= 1 || prev_c <= 1 {
129 // can't be crate style since the trees wouldn't share a prefix then. 129 // Same prefix but no use tree lists so this has to be of item style.
130 break ImportGranularityGuess::Module; 130 break ImportGranularityGuess::Item; // this overwrites CrateOrModule, technically the file doesn't adhere to anything here.
131 }
131 } 132 }
133 // Same prefix with item tree lists, has to be module style as it
134 // can't be crate style since the trees wouldn't share a prefix then.
135 break ImportGranularityGuess::Module;
132 } 136 }
133 } 137 }
134 } 138 }
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 78a2a87b3..70b11bf81 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -663,6 +663,13 @@ use foo::bar::qux;
663", 663",
664 ImportGranularityGuess::Item, 664 ImportGranularityGuess::Item,
665 ); 665 );
666 check_guess(
667 r"
668use foo::bar::Bar;
669use foo::baz;
670",
671 ImportGranularityGuess::Item,
672 );
666} 673}
667 674
668#[test] 675#[test]
@@ -682,6 +689,14 @@ use foo::{baz::{qux, quux}, bar};
682", 689",
683 ImportGranularityGuess::Module, 690 ImportGranularityGuess::Module,
684 ); 691 );
692 check_guess(
693 r"
694use foo::bar::Bar;
695use foo::baz::Baz;
696use foo::{Foo, Qux};
697",
698 ImportGranularityGuess::Module,
699 );
685} 700}
686 701
687#[test] 702#[test]
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 884fe0739..a60bc5ad9 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -259,11 +259,14 @@ impl ast::Path {
259 } 259 }
260 260
261 pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone { 261 pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
262 // cant make use of SyntaxNode::siblings, because the returned Iterator is not clone
263 successors(self.first_segment(), |p| { 262 successors(self.first_segment(), |p| {
264 p.parent_path().parent_path().and_then(|p| p.segment()) 263 p.parent_path().parent_path().and_then(|p| p.segment())
265 }) 264 })
266 } 265 }
266
267 pub fn qualifiers(&self) -> impl Iterator<Item = ast::Path> + Clone {
268 successors(self.qualifier(), |p| p.qualifier())
269 }
267} 270}
268impl ast::UseTree { 271impl ast::UseTree {
269 pub fn is_simple_path(&self) -> bool { 272 pub fn is_simple_path(&self) -> bool {
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);