aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/completion/completion_item.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/completion/completion_item.rs')
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs192
1 files changed, 2 insertions, 190 deletions
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index 95bdd59b4..f515fcc14 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -1,16 +1,8 @@
1use std::fmt; 1use std::fmt;
2 2
3use hir::{Docs, Documentation, PerNs, Resolution}; 3use hir::Documentation;
4use ra_syntax::TextRange; 4use ra_syntax::TextRange;
5use ra_text_edit::{ TextEditBuilder, TextEdit}; 5use ra_text_edit::{TextEditBuilder, TextEdit};
6use test_utils::tested_by;
7
8use crate::completion::{
9 completion_context::CompletionContext,
10 function_label,
11 const_label,
12 type_label
13};
14 6
15/// `CompletionItem` describes a single completion variant in the editor pop-up. 7/// `CompletionItem` describes a single completion variant in the editor pop-up.
16/// It is basically a POD with various properties. To construct a 8/// It is basically a POD with various properties. To construct a
@@ -255,91 +247,6 @@ impl Builder {
255 self.documentation = docs.map(Into::into); 247 self.documentation = docs.map(Into::into);
256 self 248 self
257 } 249 }
258 pub(super) fn from_resolution(
259 mut self,
260 ctx: &CompletionContext,
261 resolution: &PerNs<Resolution>,
262 ) -> Builder {
263 use hir::ModuleDef::*;
264
265 let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
266 let def = match def {
267 None => return self,
268 Some(it) => it,
269 };
270 let (kind, docs) = match def {
271 Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)),
272 Resolution::Def(Function(func)) => return self.from_function(ctx, *func),
273 Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)),
274 Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)),
275 Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
276 Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)),
277 Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)),
278 Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)),
279 Resolution::Def(Type(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
280 Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None),
281 Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None),
282 Resolution::SelfType(..) => (
283 CompletionItemKind::TypeParam, // (does this need its own kind?)
284 None,
285 ),
286 };
287 self.kind = Some(kind);
288 self.documentation = docs;
289
290 self
291 }
292
293 pub(super) fn from_function(
294 mut self,
295 ctx: &CompletionContext,
296 function: hir::Function,
297 ) -> Builder {
298 // If not an import, add parenthesis automatically.
299 if ctx.use_item_syntax.is_none() && !ctx.is_call {
300 tested_by!(inserts_parens_for_function_calls);
301 let sig = function.signature(ctx.db);
302 if sig.params().is_empty() || sig.has_self_param() && sig.params().len() == 1 {
303 self.insert_text = Some(format!("{}()$0", self.label));
304 } else {
305 self.insert_text = Some(format!("{}($0)", self.label));
306 }
307 self.insert_text_format = InsertTextFormat::Snippet;
308 }
309
310 if let Some(docs) = function.docs(ctx.db) {
311 self.documentation = Some(docs);
312 }
313
314 if let Some(label) = function_item_label(ctx, function) {
315 self.detail = Some(label);
316 }
317
318 self.kind = Some(CompletionItemKind::Function);
319 self
320 }
321
322 pub(super) fn from_const(mut self, ctx: &CompletionContext, ct: hir::Const) -> Builder {
323 if let Some(docs) = ct.docs(ctx.db) {
324 self.documentation = Some(docs);
325 }
326
327 self.detail = Some(const_item_label(ctx, ct));
328 self.kind = Some(CompletionItemKind::Const);
329
330 self
331 }
332
333 pub(super) fn from_type(mut self, ctx: &CompletionContext, ty: hir::Type) -> Builder {
334 if let Some(docs) = ty.docs(ctx.db) {
335 self.documentation = Some(docs);
336 }
337
338 self.detail = Some(type_item_label(ctx, ty));
339 self.kind = Some(CompletionItemKind::TypeAlias);
340
341 self
342 }
343} 250}
344 251
345impl<'a> Into<CompletionItem> for Builder { 252impl<'a> Into<CompletionItem> for Builder {
@@ -373,21 +280,6 @@ impl Into<Vec<CompletionItem>> for Completions {
373 } 280 }
374} 281}
375 282
376fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Option<String> {
377 let node = function.source(ctx.db).1;
378 function_label(&node)
379}
380
381fn const_item_label(ctx: &CompletionContext, ct: hir::Const) -> String {
382 let node = ct.source(ctx.db).1;
383 const_label(&node)
384}
385
386fn type_item_label(ctx: &CompletionContext, ty: hir::Type) -> String {
387 let node = ty.source(ctx.db).1;
388 type_label(&node)
389}
390
391#[cfg(test)] 283#[cfg(test)]
392pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 284pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
393 use crate::mock_analysis::{single_file_with_position, analysis_and_position}; 285 use crate::mock_analysis::{single_file_with_position, analysis_and_position};
@@ -411,83 +303,3 @@ pub(crate) fn check_completion(test_name: &str, code: &str, kind: CompletionKind
411 let kind_completions = do_completion(code, kind); 303 let kind_completions = do_completion(code, kind);
412 assert_debug_snapshot_matches!(test_name, kind_completions); 304 assert_debug_snapshot_matches!(test_name, kind_completions);
413} 305}
414
415#[cfg(test)]
416mod tests {
417 use test_utils::covers;
418
419 use super::*;
420
421 fn check_reference_completion(code: &str, expected_completions: &str) {
422 check_completion(code, expected_completions, CompletionKind::Reference);
423 }
424
425 #[test]
426 fn inserts_parens_for_function_calls() {
427 covers!(inserts_parens_for_function_calls);
428 check_reference_completion(
429 "inserts_parens_for_function_calls1",
430 r"
431 fn no_args() {}
432 fn main() { no_<|> }
433 ",
434 );
435 check_reference_completion(
436 "inserts_parens_for_function_calls2",
437 r"
438 fn with_args(x: i32, y: String) {}
439 fn main() { with_<|> }
440 ",
441 );
442 check_reference_completion(
443 "inserts_parens_for_function_calls3",
444 r"
445 struct S {}
446 impl S {
447 fn foo(&self) {}
448 }
449 fn bar(s: &S) {
450 s.f<|>
451 }
452 ",
453 )
454 }
455
456 #[test]
457 fn dont_render_function_parens_in_use_item() {
458 check_reference_completion(
459 "dont_render_function_parens_in_use_item",
460 "
461 //- /lib.rs
462 mod m { pub fn foo() {} }
463 use crate::m::f<|>;
464 ",
465 )
466 }
467
468 #[test]
469 fn dont_render_function_parens_if_already_call() {
470 check_reference_completion(
471 "dont_render_function_parens_if_already_call",
472 "
473 //- /lib.rs
474 fn frobnicate() {}
475 fn main() {
476 frob<|>();
477 }
478 ",
479 );
480 check_reference_completion(
481 "dont_render_function_parens_if_already_call_assoc_fn",
482 "
483 //- /lib.rs
484 struct Foo {}
485 impl Foo { fn new() -> Foo {} }
486 fn main() {
487 Foo::ne<|>();
488 }
489 ",
490 )
491 }
492
493}