aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/render.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/render.rs')
-rw-r--r--crates/ide_completion/src/render.rs400
1 files changed, 191 insertions, 209 deletions
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index a49a60711..d8ca18c73 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -18,54 +18,56 @@ 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,
24}; 25};
25 26
26pub(crate) fn render_field<'a>( 27pub(crate) fn render_field(
27 ctx: RenderContext<'a>, 28 ctx: RenderContext<'_>,
28 receiver: Option<hir::Name>, 29 receiver: Option<hir::Name>,
29 field: hir::Field, 30 field: hir::Field,
30 ty: &hir::Type, 31 ty: &hir::Type,
31) -> CompletionItem { 32) -> CompletionItem {
32 Render::new(ctx).render_field(receiver, field, ty) 33 render_field_(ctx, receiver, field, ty)
33} 34}
34 35
35pub(crate) fn render_tuple_field<'a>( 36pub(crate) fn render_tuple_field(
36 ctx: RenderContext<'a>, 37 ctx: RenderContext<'_>,
37 receiver: Option<hir::Name>, 38 receiver: Option<hir::Name>,
38 field: usize, 39 field: usize,
39 ty: &hir::Type, 40 ty: &hir::Type,
40) -> CompletionItem { 41) -> CompletionItem {
41 Render::new(ctx).render_tuple_field(receiver, field, ty) 42 render_tuple_field_(ctx, receiver, field, ty)
42} 43}
43 44
44pub(crate) fn render_resolution<'a>( 45pub(crate) fn render_resolution(
45 ctx: RenderContext<'a>, 46 ctx: RenderContext<'_>,
46 local_name: hir::Name, 47 local_name: hir::Name,
47 resolution: &hir::ScopeDef, 48 resolution: &hir::ScopeDef,
48) -> Option<CompletionItem> { 49) -> Option<CompletionItem> {
49 Render::new(ctx).render_resolution(local_name, None, resolution) 50 render_resolution_(ctx, local_name, None, resolution)
50} 51}
51 52
52pub(crate) fn render_resolution_with_import<'a>( 53pub(crate) fn render_resolution_with_import(
53 ctx: RenderContext<'a>, 54 ctx: RenderContext<'_>,
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)?,
60 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),
61 _ => item_name(ctx.db(), import_edit.import.original_item)?, 65 _ => item_name(ctx.db(), import_edit.import.original_item)?,
62 }; 66 };
63 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| {
64 |mut item| { 68 item.completion_kind = CompletionKind::Magic;
65 item.completion_kind = CompletionKind::Magic; 69 item
66 item 70 })
67 },
68 )
69} 71}
70 72
71/// Interface for data and methods required for items rendering. 73/// Interface for data and methods required for items rendering.
@@ -84,7 +86,7 @@ impl<'a> RenderContext<'a> {
84 } 86 }
85 87
86 fn db(&self) -> &'a RootDatabase { 88 fn db(&self) -> &'a RootDatabase {
87 &self.completion.db 89 self.completion.db
88 } 90 }
89 91
90 fn source_range(&self) -> TextRange { 92 fn source_range(&self) -> TextRange {
@@ -109,7 +111,10 @@ impl<'a> RenderContext<'a> {
109 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), 111 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
110 }; 112 };
111 is_assoc_deprecated 113 is_assoc_deprecated
112 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) 114 || assoc
115 .containing_trait_or_trait_impl(db)
116 .map(|trait_| self.is_deprecated(trait_))
117 .unwrap_or(false)
113 } 118 }
114 119
115 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> { 120 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
@@ -117,215 +122,191 @@ impl<'a> RenderContext<'a> {
117 } 122 }
118} 123}
119 124
120/// Generic renderer for completion items. 125fn render_field_(
121#[derive(Debug)] 126 ctx: RenderContext<'_>,
122struct Render<'a> { 127 receiver: Option<hir::Name>,
123 ctx: RenderContext<'a>, 128 field: hir::Field,
124} 129 ty: &hir::Type,
125 130) -> CompletionItem {
126impl<'a> Render<'a> { 131 let is_deprecated = ctx.is_deprecated(field);
127 fn new(ctx: RenderContext<'a>) -> Render<'a> { 132 let name = field.name(ctx.db()).to_string();
128 Render { ctx } 133 let mut item = CompletionItem::new(
134 CompletionKind::Reference,
135 ctx.source_range(),
136 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
137 );
138
139 item.set_relevance(CompletionRelevance {
140 type_match: compute_type_match(ctx.completion, ty),
141 exact_name_match: compute_exact_name_match(ctx.completion, &name),
142 ..CompletionRelevance::default()
143 });
144 item.kind(SymbolKind::Field)
145 .detail(ty.display(ctx.db()).to_string())
146 .set_documentation(field.docs(ctx.db()))
147 .set_deprecated(is_deprecated)
148 .lookup_by(name);
149
150 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
151 // FIXME
152 // For now we don't properly calculate the edits for ref match
153 // completions on struct fields, so we've disabled them. See #8058.
129 } 154 }
130 155
131 fn render_field( 156 item.build()
132 &self, 157}
133 receiver: Option<hir::Name>,
134 field: hir::Field,
135 ty: &hir::Type,
136 ) -> CompletionItem {
137 let is_deprecated = self.ctx.is_deprecated(field);
138 let name = field.name(self.ctx.db()).to_string();
139 let mut item = CompletionItem::new(
140 CompletionKind::Reference,
141 self.ctx.source_range(),
142 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
143 );
144 item.kind(SymbolKind::Field)
145 .detail(ty.display(self.ctx.db()).to_string())
146 .set_documentation(field.docs(self.ctx.db()))
147 .set_deprecated(is_deprecated);
148
149 item.set_relevance(CompletionRelevance {
150 type_match: compute_type_match(self.ctx.completion, ty),
151 exact_name_match: compute_exact_name_match(self.ctx.completion, &name),
152 ..CompletionRelevance::default()
153 });
154
155 if let Some(_ref_match) = compute_ref_match(self.ctx.completion, ty) {
156 // FIXME
157 // For now we don't properly calculate the edits for ref match
158 // completions on struct fields, so we've disabled them. See #8058.
159 }
160 158
161 item.build() 159fn render_tuple_field_(
162 } 160 ctx: RenderContext<'_>,
161 receiver: Option<hir::Name>,
162 field: usize,
163 ty: &hir::Type,
164) -> CompletionItem {
165 let mut item = CompletionItem::new(
166 CompletionKind::Reference,
167 ctx.source_range(),
168 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
169 );
163 170
164 fn render_tuple_field( 171 item.kind(SymbolKind::Field)
165 &self, 172 .detail(ty.display(ctx.db()).to_string())
166 receiver: Option<hir::Name>, 173 .lookup_by(field.to_string());
167 field: usize,
168 ty: &hir::Type,
169 ) -> CompletionItem {
170 let mut item = CompletionItem::new(
171 CompletionKind::Reference,
172 self.ctx.source_range(),
173 receiver
174 .map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
175 );
176 174
177 item.kind(SymbolKind::Field).detail(ty.display(self.ctx.db()).to_string()); 175 item.build()
176}
178 177
179 item.build() 178fn render_resolution_(
180 } 179 ctx: RenderContext<'_>,
180 local_name: hir::Name,
181 import_to_add: Option<ImportEdit>,
182 resolution: &hir::ScopeDef,
183) -> Option<CompletionItem> {
184 let _p = profile::span("render_resolution");
185 use hir::ModuleDef::*;
181 186
182 fn render_resolution( 187 let completion_kind = match resolution {
183 self, 188 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
184 local_name: hir::Name, 189 _ => CompletionKind::Reference,
185 import_to_add: Option<ImportEdit>, 190 };
186 resolution: &hir::ScopeDef,
187 ) -> Option<CompletionItem> {
188 let _p = profile::span("render_resolution");
189 use hir::ModuleDef::*;
190
191 let completion_kind = match resolution {
192 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
193 _ => CompletionKind::Reference,
194 };
195 191
196 let kind = match resolution { 192 let kind = match resolution {
197 hir::ScopeDef::ModuleDef(Function(func)) => { 193 hir::ScopeDef::ModuleDef(Function(func)) => {
198 return render_fn(self.ctx, import_to_add, Some(local_name), *func); 194 return render_fn(ctx, import_to_add, Some(local_name), *func);
199 } 195 }
200 hir::ScopeDef::ModuleDef(Variant(_)) 196 hir::ScopeDef::ModuleDef(Variant(_)) if ctx.completion.is_pat_or_const.is_some() => {
201 if self.ctx.completion.is_pat_or_const.is_some() => 197 CompletionItemKind::SymbolKind(SymbolKind::Variant)
202 { 198 }
203 CompletionItemKind::SymbolKind(SymbolKind::Variant) 199 hir::ScopeDef::ModuleDef(Variant(var)) => {
204 } 200 let item = render_variant(ctx, import_to_add, Some(local_name), *var, None);
205 hir::ScopeDef::ModuleDef(Variant(var)) => { 201 return Some(item);
206 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); 202 }
207 return Some(item); 203 hir::ScopeDef::MacroDef(mac) => {
208 } 204 let item = render_macro(ctx, import_to_add, local_name, *mac);
209 hir::ScopeDef::MacroDef(mac) => { 205 return item;
210 let item = render_macro(self.ctx, import_to_add, local_name, *mac); 206 }
211 return item;
212 }
213 207
214 hir::ScopeDef::ModuleDef(Module(..)) => { 208 hir::ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
215 CompletionItemKind::SymbolKind(SymbolKind::Module) 209 hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
216 } 210 hir::Adt::Struct(_) => SymbolKind::Struct,
217 hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { 211 hir::Adt::Union(_) => SymbolKind::Union,
218 hir::Adt::Struct(_) => SymbolKind::Struct, 212 hir::Adt::Enum(_) => SymbolKind::Enum,
219 hir::Adt::Union(_) => SymbolKind::Union, 213 }),
220 hir::Adt::Enum(_) => SymbolKind::Enum, 214 hir::ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
221 }), 215 hir::ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
222 hir::ScopeDef::ModuleDef(Const(..)) => { 216 hir::ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
223 CompletionItemKind::SymbolKind(SymbolKind::Const) 217 hir::ScopeDef::ModuleDef(TypeAlias(..)) => {
224 } 218 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
225 hir::ScopeDef::ModuleDef(Static(..)) => { 219 }
226 CompletionItemKind::SymbolKind(SymbolKind::Static) 220 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
227 } 221 hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
228 hir::ScopeDef::ModuleDef(Trait(..)) => { 222 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
229 CompletionItemKind::SymbolKind(SymbolKind::Trait) 223 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
230 } 224 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
231 hir::ScopeDef::ModuleDef(TypeAlias(..)) => { 225 }),
232 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) 226 hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
233 } 227 hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
234 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 228 hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => {
235 hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { 229 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
236 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, 230 }
237 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, 231 hir::ScopeDef::Unknown => {
238 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, 232 let mut item = CompletionItem::new(
239 }), 233 CompletionKind::Reference,
240 hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), 234 ctx.source_range(),
241 hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), 235 local_name.to_string(),
242 hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => { 236 );
243 CompletionItemKind::SymbolKind(SymbolKind::SelfParam) 237 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
244 } 238 return Some(item.build());
245 hir::ScopeDef::Unknown => { 239 }
246 let mut item = CompletionItem::new( 240 };
247 CompletionKind::Reference,
248 self.ctx.source_range(),
249 local_name.to_string(),
250 );
251 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
252 return Some(item.build());
253 }
254 };
255 241
256 let local_name = local_name.to_string(); 242 let local_name = local_name.to_string();
257 let mut item = 243 let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
258 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); 244 if let hir::ScopeDef::Local(local) = resolution {
259 if let hir::ScopeDef::Local(local) = resolution { 245 let ty = local.ty(ctx.db());
260 let ty = local.ty(self.ctx.db()); 246 if !ty.is_unknown() {
261 if !ty.is_unknown() { 247 item.detail(ty.display(ctx.db()).to_string());
262 item.detail(ty.display(self.ctx.db()).to_string()); 248 }
263 }
264 249
265 item.set_relevance(CompletionRelevance { 250 item.set_relevance(CompletionRelevance {
266 type_match: compute_type_match(self.ctx.completion, &ty), 251 type_match: compute_type_match(ctx.completion, &ty),
267 exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name), 252 exact_name_match: compute_exact_name_match(ctx.completion, &local_name),
268 is_local: true, 253 is_local: true,
269 ..CompletionRelevance::default() 254 ..CompletionRelevance::default()
270 }); 255 });
271 256
272 if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) { 257 if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) {
273 item.ref_match(ref_match); 258 item.ref_match(ref_match);
274 } 259 }
275 }; 260 };
276 261
277 // Add `<>` for generic types 262 // Add `<>` for generic types
278 if self.ctx.completion.is_path_type 263 if matches!(
279 && !self.ctx.completion.has_type_args 264 ctx.completion.path_context,
280 && self.ctx.completion.config.add_call_parenthesis 265 Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
281 { 266 ) && ctx.completion.config.add_call_parenthesis
282 if let Some(cap) = self.ctx.snippet_cap() { 267 {
283 let has_non_default_type_params = match resolution { 268 if let Some(cap) = ctx.snippet_cap() {
284 hir::ScopeDef::ModuleDef(Adt(it)) => { 269 let has_non_default_type_params = match resolution {
285 it.has_non_default_type_params(self.ctx.db()) 270 hir::ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()),
286 } 271 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()),
287 hir::ScopeDef::ModuleDef(TypeAlias(it)) => { 272 _ => false,
288 it.has_non_default_type_params(self.ctx.db()) 273 };
289 } 274 if has_non_default_type_params {
290 _ => false, 275 cov_mark::hit!(inserts_angle_brackets_for_generics);
291 }; 276 item.lookup_by(local_name.clone())
292 if has_non_default_type_params { 277 .label(format!("{}<…>", local_name))
293 cov_mark::hit!(inserts_angle_brackets_for_generics); 278 .insert_snippet(cap, format!("{}<$0>", local_name));
294 item.lookup_by(local_name.clone())
295 .label(format!("{}<…>", local_name))
296 .insert_snippet(cap, format!("{}<$0>", local_name));
297 }
298 } 279 }
299 } 280 }
300 item.kind(kind)
301 .add_import(import_to_add)
302 .set_documentation(self.docs(resolution))
303 .set_deprecated(self.is_deprecated(resolution));
304 Some(item.build())
305 } 281 }
282 item.kind(kind)
283 .add_import(import_to_add)
284 .set_documentation(scope_def_docs(ctx.db(), resolution))
285 .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
286 Some(item.build())
287}
306 288
307 fn docs(&self, resolution: &hir::ScopeDef) -> Option<hir::Documentation> { 289fn scope_def_docs(db: &RootDatabase, resolution: &hir::ScopeDef) -> Option<hir::Documentation> {
308 use hir::ModuleDef::*; 290 use hir::ModuleDef::*;
309 match resolution { 291 match resolution {
310 hir::ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()), 292 hir::ScopeDef::ModuleDef(Module(it)) => it.docs(db),
311 hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()), 293 hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
312 hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()), 294 hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
313 hir::ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()), 295 hir::ScopeDef::ModuleDef(Const(it)) => it.docs(db),
314 hir::ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()), 296 hir::ScopeDef::ModuleDef(Static(it)) => it.docs(db),
315 hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()), 297 hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
316 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()), 298 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
317 _ => None, 299 _ => None,
318 }
319 } 300 }
301}
320 302
321 fn is_deprecated(&self, resolution: &hir::ScopeDef) -> bool { 303fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: &hir::ScopeDef) -> bool {
322 match resolution { 304 match resolution {
323 hir::ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), 305 hir::ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(*it),
324 hir::ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), 306 hir::ScopeDef::MacroDef(it) => ctx.is_deprecated(*it),
325 hir::ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), 307 hir::ScopeDef::GenericParam(it) => ctx.is_deprecated(*it),
326 hir::ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), 308 hir::ScopeDef::AdtSelfType(it) => ctx.is_deprecated(*it),
327 _ => false, 309 _ => false,
328 }
329 } 310 }
330} 311}
331 312
@@ -1026,6 +1007,7 @@ fn go(world: &WorldSnapshot) { go(w$0) }
1026 1007
1027 #[test] 1008 #[test]
1028 fn too_many_arguments() { 1009 fn too_many_arguments() {
1010 cov_mark::check!(too_many_arguments);
1029 check_relevance( 1011 check_relevance(
1030 r#" 1012 r#"
1031struct Foo; 1013struct Foo;