aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/render')
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs55
-rw-r--r--crates/ide_completion/src/render/function.rs50
-rw-r--r--crates/ide_completion/src/render/macro_.rs15
3 files changed, 80 insertions, 40 deletions
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index 0c0c71134..28f056e77 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -1,6 +1,8 @@
1//! Renderer for `enum` variants. 1//! Renderer for `enum` variants.
2 2
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 3use std::iter;
4
5use hir::{HasAttrs, HirDisplay};
4use ide_db::SymbolKind; 6use ide_db::SymbolKind;
5use itertools::Itertools; 7use itertools::Itertools;
6 8
@@ -13,9 +15,9 @@ use crate::{
13pub(crate) fn render_variant<'a>( 15pub(crate) fn render_variant<'a>(
14 ctx: RenderContext<'a>, 16 ctx: RenderContext<'a>,
15 import_to_add: Option<ImportEdit>, 17 import_to_add: Option<ImportEdit>,
16 local_name: Option<String>, 18 local_name: Option<hir::Name>,
17 variant: hir::Variant, 19 variant: hir::Variant,
18 path: Option<ModPath>, 20 path: Option<hir::ModPath>,
19) -> CompletionItem { 21) -> CompletionItem {
20 let _p = profile::span("render_enum_variant"); 22 let _p = profile::span("render_enum_variant");
21 EnumRender::new(ctx, local_name, variant, path).render(import_to_add) 23 EnumRender::new(ctx, local_name, variant, path).render(import_to_add)
@@ -24,42 +26,45 @@ pub(crate) fn render_variant<'a>(
24#[derive(Debug)] 26#[derive(Debug)]
25struct EnumRender<'a> { 27struct EnumRender<'a> {
26 ctx: RenderContext<'a>, 28 ctx: RenderContext<'a>,
27 name: String, 29 name: hir::Name,
28 variant: hir::Variant, 30 variant: hir::Variant,
29 path: Option<ModPath>, 31 path: Option<hir::ModPath>,
30 qualified_name: String, 32 qualified_name: hir::ModPath,
31 short_qualified_name: String, 33 short_qualified_name: hir::ModPath,
32 variant_kind: StructKind, 34 variant_kind: hir::StructKind,
33} 35}
34 36
35impl<'a> EnumRender<'a> { 37impl<'a> EnumRender<'a> {
36 fn new( 38 fn new(
37 ctx: RenderContext<'a>, 39 ctx: RenderContext<'a>,
38 local_name: Option<String>, 40 local_name: Option<hir::Name>,
39 variant: hir::Variant, 41 variant: hir::Variant,
40 path: Option<ModPath>, 42 path: Option<hir::ModPath>,
41 ) -> EnumRender<'a> { 43 ) -> EnumRender<'a> {
42 let name = local_name.unwrap_or_else(|| variant.name(ctx.db()).to_string()); 44 let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
43 let variant_kind = variant.kind(ctx.db()); 45 let variant_kind = variant.kind(ctx.db());
44 46
45 let (qualified_name, short_qualified_name) = match &path { 47 let (qualified_name, short_qualified_name) = match &path {
46 Some(path) => { 48 Some(path) => {
47 let full = path.to_string(); 49 let short = hir::ModPath::from_segments(
48 let segments = path.segments(); 50 hir::PathKind::Plain,
49 let short = segments[segments.len().saturating_sub(2)..].iter().join("::"); 51 path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(),
50 (full, short) 52 );
53 (path.clone(), short)
51 } 54 }
52 None => (name.to_string(), name.to_string()), 55 None => (
56 hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())),
57 hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())),
58 ),
53 }; 59 };
54 60
55 EnumRender { ctx, name, variant, path, qualified_name, short_qualified_name, variant_kind } 61 EnumRender { ctx, name, variant, path, qualified_name, short_qualified_name, variant_kind }
56 } 62 }
57
58 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { 63 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
59 let mut item = CompletionItem::new( 64 let mut item = CompletionItem::new(
60 CompletionKind::Reference, 65 CompletionKind::Reference,
61 self.ctx.source_range(), 66 self.ctx.source_range(),
62 self.qualified_name.clone(), 67 self.qualified_name.to_string(),
63 ); 68 );
64 item.kind(SymbolKind::Variant) 69 item.kind(SymbolKind::Variant)
65 .set_documentation(self.variant.docs(self.ctx.db())) 70 .set_documentation(self.variant.docs(self.ctx.db()))
@@ -67,12 +72,16 @@ impl<'a> EnumRender<'a> {
67 .add_import(import_to_add) 72 .add_import(import_to_add)
68 .detail(self.detail()); 73 .detail(self.detail());
69 74
70 if self.variant_kind == StructKind::Tuple { 75 if self.variant_kind == hir::StructKind::Tuple {
71 cov_mark::hit!(inserts_parens_for_tuple_enums); 76 cov_mark::hit!(inserts_parens_for_tuple_enums);
72 let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len()); 77 let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len());
73 item.add_call_parens(self.ctx.completion, self.short_qualified_name, params); 78 item.add_call_parens(
79 self.ctx.completion,
80 self.short_qualified_name.to_string(),
81 params,
82 );
74 } else if self.path.is_some() { 83 } else if self.path.is_some() {
75 item.lookup_by(self.short_qualified_name); 84 item.lookup_by(self.short_qualified_name.to_string());
76 } 85 }
77 86
78 let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db); 87 let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db);
@@ -96,11 +105,11 @@ impl<'a> EnumRender<'a> {
96 .map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db()))); 105 .map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db())));
97 106
98 match self.variant_kind { 107 match self.variant_kind {
99 StructKind::Tuple | StructKind::Unit => format!( 108 hir::StructKind::Tuple | hir::StructKind::Unit => format!(
100 "({})", 109 "({})",
101 detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ") 110 detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ")
102 ), 111 ),
103 StructKind::Record => format!( 112 hir::StructKind::Record => format!(
104 "{{ {} }}", 113 "{{ {} }}",
105 detail_types 114 detail_types
106 .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string())) 115 .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string()))
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index d681e2c91..3ec77ca0f 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -1,6 +1,6 @@
1//! Renderer for function calls. 1//! Renderer for function calls.
2 2
3use hir::{HasSource, HirDisplay, Type}; 3use hir::{HasSource, HirDisplay};
4use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use itertools::Itertools; 5use itertools::Itertools;
6use syntax::ast::Fn; 6use syntax::ast::Fn;
@@ -16,27 +16,29 @@ use crate::{
16pub(crate) fn render_fn<'a>( 16pub(crate) fn render_fn<'a>(
17 ctx: RenderContext<'a>, 17 ctx: RenderContext<'a>,
18 import_to_add: Option<ImportEdit>, 18 import_to_add: Option<ImportEdit>,
19 local_name: Option<String>, 19 local_name: Option<hir::Name>,
20 fn_: hir::Function, 20 fn_: hir::Function,
21) -> Option<CompletionItem> { 21) -> Option<CompletionItem> {
22 let _p = profile::span("render_fn"); 22 let _p = profile::span("render_fn");
23 Some(FunctionRender::new(ctx, local_name, fn_, false)?.render(import_to_add)) 23 Some(FunctionRender::new(ctx, None, local_name, fn_, false)?.render(import_to_add))
24} 24}
25 25
26pub(crate) fn render_method<'a>( 26pub(crate) fn render_method<'a>(
27 ctx: RenderContext<'a>, 27 ctx: RenderContext<'a>,
28 import_to_add: Option<ImportEdit>, 28 import_to_add: Option<ImportEdit>,
29 local_name: Option<String>, 29 receiver: Option<hir::Name>,
30 local_name: Option<hir::Name>,
30 fn_: hir::Function, 31 fn_: hir::Function,
31) -> Option<CompletionItem> { 32) -> Option<CompletionItem> {
32 let _p = profile::span("render_method"); 33 let _p = profile::span("render_method");
33 Some(FunctionRender::new(ctx, local_name, fn_, true)?.render(import_to_add)) 34 Some(FunctionRender::new(ctx, receiver, local_name, fn_, true)?.render(import_to_add))
34} 35}
35 36
36#[derive(Debug)] 37#[derive(Debug)]
37struct FunctionRender<'a> { 38struct FunctionRender<'a> {
38 ctx: RenderContext<'a>, 39 ctx: RenderContext<'a>,
39 name: String, 40 name: String,
41 receiver: Option<hir::Name>,
40 func: hir::Function, 42 func: hir::Function,
41 ast_node: Fn, 43 ast_node: Fn,
42 is_method: bool, 44 is_method: bool,
@@ -45,18 +47,22 @@ struct FunctionRender<'a> {
45impl<'a> FunctionRender<'a> { 47impl<'a> FunctionRender<'a> {
46 fn new( 48 fn new(
47 ctx: RenderContext<'a>, 49 ctx: RenderContext<'a>,
48 local_name: Option<String>, 50 receiver: Option<hir::Name>,
51 local_name: Option<hir::Name>,
49 fn_: hir::Function, 52 fn_: hir::Function,
50 is_method: bool, 53 is_method: bool,
51 ) -> Option<FunctionRender<'a>> { 54 ) -> Option<FunctionRender<'a>> {
52 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); 55 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db())).to_string();
53 let ast_node = fn_.source(ctx.db())?.value; 56 let ast_node = fn_.source(ctx.db())?.value;
54 57
55 Some(FunctionRender { ctx, name, func: fn_, ast_node, is_method }) 58 Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method })
56 } 59 }
57 60
58 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { 61 fn render(mut self, import_to_add: Option<ImportEdit>) -> CompletionItem {
59 let params = self.params(); 62 let params = self.params();
63 if let Some(receiver) = &self.receiver {
64 self.name = format!("{}.{}", receiver, &self.name)
65 }
60 let mut item = CompletionItem::new( 66 let mut item = CompletionItem::new(
61 CompletionKind::Reference, 67 CompletionKind::Reference,
62 self.ctx.source_range(), 68 self.ctx.source_range(),
@@ -74,7 +80,7 @@ impl<'a> FunctionRender<'a> {
74 let ret_type = self.func.ret_type(self.ctx.db()); 80 let ret_type = self.func.ret_type(self.ctx.db());
75 item.set_relevance(CompletionRelevance { 81 item.set_relevance(CompletionRelevance {
76 type_match: compute_type_match(self.ctx.completion, &ret_type), 82 type_match: compute_type_match(self.ctx.completion, &ret_type),
77 exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()), 83 exact_name_match: compute_exact_name_match(self.ctx.completion, &self.name),
78 ..CompletionRelevance::default() 84 ..CompletionRelevance::default()
79 }); 85 });
80 86
@@ -129,7 +135,7 @@ impl<'a> FunctionRender<'a> {
129 format!("-> {}", ret_ty.display(self.ctx.db())) 135 format!("-> {}", ret_ty.display(self.ctx.db()))
130 } 136 }
131 137
132 fn add_arg(&self, arg: &str, ty: &Type) -> String { 138 fn add_arg(&self, arg: &str, ty: &hir::Type) -> String {
133 if let Some(derefed_ty) = ty.remove_ref() { 139 if let Some(derefed_ty) = ty.remove_ref() {
134 for (name, local) in self.ctx.completion.locals.iter() { 140 for (name, local) in self.ctx.completion.locals.iter() {
135 if name == arg && local.ty(self.ctx.db()) == derefed_ty { 141 if name == arg && local.ty(self.ctx.db()) == derefed_ty {
@@ -148,7 +154,7 @@ impl<'a> FunctionRender<'a> {
148 }; 154 };
149 155
150 let mut params_pats = Vec::new(); 156 let mut params_pats = Vec::new();
151 let params_ty = if self.ctx.completion.dot_receiver.is_some() { 157 let params_ty = if self.ctx.completion.dot_receiver.is_some() || self.receiver.is_some() {
152 self.func.method_params(self.ctx.db()).unwrap_or_default() 158 self.func.method_params(self.ctx.db()).unwrap_or_default()
153 } else { 159 } else {
154 if let Some(s) = ast_params.self_param() { 160 if let Some(s) = ast_params.self_param() {
@@ -255,6 +261,26 @@ fn bar(s: &S) {
255} 261}
256"#, 262"#,
257 ); 263 );
264
265 check_edit(
266 "self.foo",
267 r#"
268struct S {}
269impl S {
270 fn foo(&self, x: i32) {
271 $0
272 }
273}
274"#,
275 r#"
276struct S {}
277impl S {
278 fn foo(&self, x: i32) {
279 self.foo(${1:x})$0
280 }
281}
282"#,
283 );
258 } 284 }
259 285
260 #[test] 286 #[test]
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 7578ad50b..0dfba8acc 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -1,6 +1,6 @@
1//! Renderer for macro invocations. 1//! Renderer for macro invocations.
2 2
3use hir::{Documentation, HasSource}; 3use hir::HasSource;
4use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use syntax::display::macro_label; 5use syntax::display::macro_label;
6 6
@@ -12,7 +12,7 @@ use crate::{
12pub(crate) fn render_macro<'a>( 12pub(crate) fn render_macro<'a>(
13 ctx: RenderContext<'a>, 13 ctx: RenderContext<'a>,
14 import_to_add: Option<ImportEdit>, 14 import_to_add: Option<ImportEdit>,
15 name: String, 15 name: hir::Name,
16 macro_: hir::MacroDef, 16 macro_: hir::MacroDef,
17) -> Option<CompletionItem> { 17) -> Option<CompletionItem> {
18 let _p = profile::span("render_macro"); 18 let _p = profile::span("render_macro");
@@ -24,13 +24,14 @@ struct MacroRender<'a> {
24 ctx: RenderContext<'a>, 24 ctx: RenderContext<'a>,
25 name: String, 25 name: String,
26 macro_: hir::MacroDef, 26 macro_: hir::MacroDef,
27 docs: Option<Documentation>, 27 docs: Option<hir::Documentation>,
28 bra: &'static str, 28 bra: &'static str,
29 ket: &'static str, 29 ket: &'static str,
30} 30}
31 31
32impl<'a> MacroRender<'a> { 32impl<'a> MacroRender<'a> {
33 fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRender<'a> { 33 fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> {
34 let name = name.to_string();
34 let docs = ctx.docs(macro_); 35 let docs = ctx.docs(macro_);
35 let docs_str = docs.as_ref().map_or("", |s| s.as_str()); 36 let docs_str = docs.as_ref().map_or("", |s| s.as_str());
36 let (bra, ket) = guess_macro_braces(&name, docs_str); 37 let (bra, ket) = guess_macro_braces(&name, docs_str);
@@ -74,7 +75,11 @@ impl<'a> MacroRender<'a> {
74 if self.needs_bang() && self.ctx.snippet_cap().is_some() { 75 if self.needs_bang() && self.ctx.snippet_cap().is_some() {
75 format!("{}!{}…{}", self.name, self.bra, self.ket) 76 format!("{}!{}…{}", self.name, self.bra, self.ket)
76 } else { 77 } else {
77 self.banged_name() 78 if self.macro_.kind() == hir::MacroKind::Derive {
79 self.name.to_string()
80 } else {
81 self.banged_name()
82 }
78 } 83 }
79 } 84 }
80 85