aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src')
-rw-r--r--crates/completion/src/completions.rs5
-rw-r--r--crates/completion/src/completions/attribute.rs2
-rw-r--r--crates/completion/src/completions/postfix.rs2
-rw-r--r--crates/completion/src/completions/postfix/format_like.rs13
-rw-r--r--crates/completion/src/completions/record.rs68
-rw-r--r--crates/completion/src/completions/trait_impl.rs47
-rw-r--r--crates/completion/src/completions/unqualified_path.rs15
-rw-r--r--crates/completion/src/lib.rs2
-rw-r--r--crates/completion/src/render.rs3
-rw-r--r--crates/completion/src/render/const_.rs8
-rw-r--r--crates/completion/src/render/function.rs10
-rw-r--r--crates/completion/src/render/macro_.rs15
-rw-r--r--crates/completion/src/render/type_alias.rs8
13 files changed, 137 insertions, 61 deletions
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index d9fe13485..00c9e76f0 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -106,8 +106,9 @@ impl Completions {
106 func: hir::Function, 106 func: hir::Function,
107 local_name: Option<String>, 107 local_name: Option<String>,
108 ) { 108 ) {
109 let item = render_fn(RenderContext::new(ctx), None, local_name, func); 109 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) {
110 self.add(item) 110 self.add(item)
111 }
111 } 112 }
112 113
113 pub(crate) fn add_variant_pat( 114 pub(crate) fn add_variant_pat(
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index 19ce2482f..8695eed39 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -234,7 +234,7 @@ fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<Strin
234 current_derive = String::new(); 234 current_derive = String::new();
235 } 235 }
236 } else { 236 } else {
237 current_derive.push_str(token.to_string().trim()); 237 current_derive.push_str(token.text().trim());
238 } 238 }
239 } 239 }
240 240
diff --git a/crates/completion/src/completions/postfix.rs b/crates/completion/src/completions/postfix.rs
index d6db82a93..3883d6d21 100644
--- a/crates/completion/src/completions/postfix.rs
+++ b/crates/completion/src/completions/postfix.rs
@@ -502,7 +502,7 @@ fn main() {
502 #[test] 502 #[test]
503 fn postfix_completion_for_format_like_strings() { 503 fn postfix_completion_for_format_like_strings() {
504 check_edit( 504 check_edit(
505 "fmt", 505 "format",
506 r#"fn main() { "{some_var:?}".<|> }"#, 506 r#"fn main() { "{some_var:?}".<|> }"#,
507 r#"fn main() { format!("{:?}", some_var) }"#, 507 r#"fn main() { format!("{:?}", some_var) }"#,
508 ); 508 );
diff --git a/crates/completion/src/completions/postfix/format_like.rs b/crates/completion/src/completions/postfix/format_like.rs
index 88ba86acb..def4b13fb 100644
--- a/crates/completion/src/completions/postfix/format_like.rs
+++ b/crates/completion/src/completions/postfix/format_like.rs
@@ -22,7 +22,7 @@ use syntax::ast::{self, AstToken};
22 22
23/// Mapping ("postfix completion item" => "macro to use") 23/// Mapping ("postfix completion item" => "macro to use")
24static KINDS: &[(&str, &str)] = &[ 24static KINDS: &[(&str, &str)] = &[
25 ("fmt", "format!"), 25 ("format", "format!"),
26 ("panic", "panic!"), 26 ("panic", "panic!"),
27 ("println", "println!"), 27 ("println", "println!"),
28 ("eprintln", "eprintln!"), 28 ("eprintln", "eprintln!"),
@@ -108,7 +108,8 @@ impl FormatStrParser {
108 // "{MyStruct { val_a: 0, val_b: 1 }}". 108 // "{MyStruct { val_a: 0, val_b: 1 }}".
109 let mut inexpr_open_count = 0; 109 let mut inexpr_open_count = 0;
110 110
111 for chr in self.input.chars() { 111 let mut chars = self.input.chars().peekable();
112 while let Some(chr) = chars.next() {
112 match (self.state, chr) { 113 match (self.state, chr) {
113 (State::NotExpr, '{') => { 114 (State::NotExpr, '{') => {
114 self.output.push(chr); 115 self.output.push(chr);
@@ -157,6 +158,11 @@ impl FormatStrParser {
157 inexpr_open_count -= 1; 158 inexpr_open_count -= 1;
158 } 159 }
159 } 160 }
161 (State::Expr, ':') if chars.peek().copied() == Some(':') => {
162 // path seperator
163 current_expr.push_str("::");
164 chars.next();
165 }
160 (State::Expr, ':') => { 166 (State::Expr, ':') => {
161 if inexpr_open_count == 0 { 167 if inexpr_open_count == 0 {
162 // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" 168 // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
@@ -249,6 +255,9 @@ mod tests {
249 expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]], 255 expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
250 ), 256 ),
251 ("{ 2 + 2 }", expect![["{}; 2 + 2"]]), 257 ("{ 2 + 2 }", expect![["{}; 2 + 2"]]),
258 ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]),
259 ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]),
260 ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]),
252 ]; 261 ];
253 262
254 for (input, output) in test_vector { 263 for (input, output) in test_vector {
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs
index 91bf4a8ad..e58b9a274 100644
--- a/crates/completion/src/completions/record.rs
+++ b/crates/completion/src/completions/record.rs
@@ -20,13 +20,17 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
20 20
21 let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); 21 let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
22 if impl_default_trait && !missing_fields.is_empty() { 22 if impl_default_trait && !missing_fields.is_empty() {
23 let completion_text = "..Default::default()";
24 let completion_text = completion_text
25 .strip_prefix(ctx.token.to_string().as_str())
26 .unwrap_or(completion_text);
23 acc.add( 27 acc.add(
24 CompletionItem::new( 28 CompletionItem::new(
25 CompletionKind::Snippet, 29 CompletionKind::Snippet,
26 ctx.source_range(), 30 ctx.source_range(),
27 "..Default::default()", 31 "..Default::default()",
28 ) 32 )
29 .insert_text("..Default::default()") 33 .insert_text(completion_text)
30 .kind(CompletionItemKind::Field) 34 .kind(CompletionItemKind::Field)
31 .build(), 35 .build(),
32 ); 36 );
@@ -48,7 +52,10 @@ mod tests {
48 use expect_test::{expect, Expect}; 52 use expect_test::{expect, Expect};
49 use ide_db::helpers::FamousDefs; 53 use ide_db::helpers::FamousDefs;
50 54
51 use crate::{test_utils::completion_list, CompletionKind}; 55 use crate::{
56 test_utils::{self, completion_list},
57 CompletionKind,
58 };
52 59
53 fn check(ra_fixture: &str, expect: Expect) { 60 fn check(ra_fixture: &str, expect: Expect) {
54 let actual = completion_list(ra_fixture, CompletionKind::Reference); 61 let actual = completion_list(ra_fixture, CompletionKind::Reference);
@@ -63,6 +70,18 @@ mod tests {
63 expect.assert_eq(&actual); 70 expect.assert_eq(&actual);
64 } 71 }
65 72
73 fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
74 test_utils::check_edit(
75 what,
76 &format!(
77 "//- /main.rs crate:main deps:core{}\n{}",
78 ra_fixture_before,
79 FamousDefs::FIXTURE,
80 ),
81 &(ra_fixture_after.to_owned() + "\n"),
82 );
83 }
84
66 #[test] 85 #[test]
67 fn test_record_literal_field_default() { 86 fn test_record_literal_field_default() {
68 let test_code = r#" 87 let test_code = r#"
@@ -102,6 +121,51 @@ fn process(f: S) {
102 } 121 }
103 122
104 #[test] 123 #[test]
124 fn test_record_literal_field_default_completion() {
125 check_edit(
126 "..Default::default()",
127 r#"
128struct S { foo: u32, bar: usize }
129
130impl core::default::Default for S {
131 fn default() -> Self {
132 S {
133 foo: 0,
134 bar: 0,
135 }
136 }
137}
138
139fn process(f: S) {
140 let other = S {
141 foo: 5,
142 .<|>
143 };
144}
145"#,
146 r#"
147struct S { foo: u32, bar: usize }
148
149impl core::default::Default for S {
150 fn default() -> Self {
151 S {
152 foo: 0,
153 bar: 0,
154 }
155 }
156}
157
158fn process(f: S) {
159 let other = S {
160 foo: 5,
161 ..Default::default()
162 };
163}
164"#,
165 );
166 }
167
168 #[test]
105 fn test_record_literal_field_without_default() { 169 fn test_record_literal_field_without_default() {
106 let test_code = r#" 170 let test_code = r#"
107struct S { foo: u32, bar: usize } 171struct S { foo: u32, bar: usize }
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index c4e0d0669..54bb897e9 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -156,19 +156,21 @@ fn add_function_impl(
156 }; 156 };
157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
158 158
159 let function_decl = function_declaration(&func.source(ctx.db).value); 159 if let Some(src) = func.source(ctx.db) {
160 match ctx.config.snippet_cap { 160 let function_decl = function_declaration(&src.value);
161 Some(cap) => { 161 match ctx.config.snippet_cap {
162 let snippet = format!("{} {{\n $0\n}}", function_decl); 162 Some(cap) => {
163 builder.snippet_edit(cap, TextEdit::replace(range, snippet)) 163 let snippet = format!("{} {{\n $0\n}}", function_decl);
164 } 164 builder.snippet_edit(cap, TextEdit::replace(range, snippet))
165 None => { 165 }
166 let header = format!("{} {{", function_decl); 166 None => {
167 builder.text_edit(TextEdit::replace(range, header)) 167 let header = format!("{} {{", function_decl);
168 builder.text_edit(TextEdit::replace(range, header))
169 }
168 } 170 }
171 .kind(completion_kind)
172 .add_to(acc);
169 } 173 }
170 .kind(completion_kind)
171 .add_to(acc);
172} 174}
173 175
174fn add_type_alias_impl( 176fn add_type_alias_impl(
@@ -200,16 +202,19 @@ fn add_const_impl(
200 let const_name = const_.name(ctx.db).map(|n| n.to_string()); 202 let const_name = const_.name(ctx.db).map(|n| n.to_string());
201 203
202 if let Some(const_name) = const_name { 204 if let Some(const_name) = const_name {
203 let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); 205 if let Some(source) = const_.source(ctx.db) {
204 206 let snippet = make_const_compl_syntax(&source.value);
205 let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); 207
206 208 let range =
207 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 209 TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
208 .text_edit(TextEdit::replace(range, snippet)) 210
209 .lookup_by(const_name) 211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
210 .kind(CompletionItemKind::Const) 212 .text_edit(TextEdit::replace(range, snippet))
211 .set_documentation(const_.docs(ctx.db)) 213 .lookup_by(const_name)
212 .add_to(acc); 214 .kind(CompletionItemKind::Const)
215 .set_documentation(const_.docs(ctx.db))
216 .add_to(acc);
217 }
213 } 218 }
214} 219}
215 220
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index d09849752..81a6d00e2 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -101,8 +101,9 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
101// 101//
102// .Fuzzy search details 102// .Fuzzy search details
103// 103//
104// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only 104// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
105// (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers. 105// (i.e. in `HashMap` in the `std::collections::HashMap` path).
106// For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
106// 107//
107// .Merge Behavior 108// .Merge Behavior
108// 109//
@@ -126,15 +127,20 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
126 let _p = profile::span("fuzzy_completion"); 127 let _p = profile::span("fuzzy_completion");
127 let potential_import_name = ctx.token.to_string(); 128 let potential_import_name = ctx.token.to_string();
128 129
130 if potential_import_name.len() < 2 {
131 return None;
132 }
133
129 let current_module = ctx.scope.module()?; 134 let current_module = ctx.scope.module()?;
130 let anchor = ctx.name_ref_syntax.as_ref()?; 135 let anchor = ctx.name_ref_syntax.as_ref()?;
131 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; 136 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
132 137
138 let user_input_lowercased = potential_import_name.to_lowercase();
133 let mut all_mod_paths = imports_locator::find_similar_imports( 139 let mut all_mod_paths = imports_locator::find_similar_imports(
134 &ctx.sema, 140 &ctx.sema,
135 ctx.krate?, 141 ctx.krate?,
136 Some(100), 142 Some(40),
137 &potential_import_name, 143 potential_import_name,
138 true, 144 true,
139 ) 145 )
140 .filter_map(|import_candidate| { 146 .filter_map(|import_candidate| {
@@ -150,7 +156,6 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
150 .filter(|(mod_path, _)| mod_path.len() > 1) 156 .filter(|(mod_path, _)| mod_path.len() > 1)
151 .collect::<Vec<_>>(); 157 .collect::<Vec<_>>();
152 158
153 let user_input_lowercased = potential_import_name.to_lowercase();
154 all_mod_paths.sort_by_cached_key(|(mod_path, _)| { 159 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
155 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) 160 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
156 }); 161 });
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index 8e27bb153..c57d05bbe 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -137,7 +137,7 @@ pub fn resolve_completion_edits(
137 config: &CompletionConfig, 137 config: &CompletionConfig,
138 position: FilePosition, 138 position: FilePosition,
139 full_import_path: &str, 139 full_import_path: &str,
140 imported_name: &str, 140 imported_name: String,
141) -> Option<Vec<TextEdit>> { 141) -> Option<Vec<TextEdit>> {
142 let ctx = CompletionContext::new(db, position, config)?; 142 let ctx = CompletionContext::new(db, position, config)?;
143 let anchor = ctx.name_ref_syntax.as_ref()?; 143 let anchor = ctx.name_ref_syntax.as_ref()?;
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 1ba7201a1..ac0b2a513 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -157,8 +157,7 @@ impl<'a> Render<'a> {
157 157
158 let kind = match resolution { 158 let kind = match resolution {
159 ScopeDef::ModuleDef(Function(func)) => { 159 ScopeDef::ModuleDef(Function(func)) => {
160 let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); 160 return render_fn(self.ctx, import_to_add, Some(local_name), *func);
161 return Some(item);
162 } 161 }
163 ScopeDef::ModuleDef(Variant(_)) 162 ScopeDef::ModuleDef(Variant(_))
164 if self.ctx.completion.is_pat_binding_or_const 163 if self.ctx.completion.is_pat_binding_or_const
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs
index 039bdabc0..ce924f309 100644
--- a/crates/completion/src/render/const_.rs
+++ b/crates/completion/src/render/const_.rs
@@ -15,7 +15,7 @@ pub(crate) fn render_const<'a>(
15 ctx: RenderContext<'a>, 15 ctx: RenderContext<'a>,
16 const_: hir::Const, 16 const_: hir::Const,
17) -> Option<CompletionItem> { 17) -> Option<CompletionItem> {
18 ConstRender::new(ctx, const_).render() 18 ConstRender::new(ctx, const_)?.render()
19} 19}
20 20
21#[derive(Debug)] 21#[derive(Debug)]
@@ -26,9 +26,9 @@ struct ConstRender<'a> {
26} 26}
27 27
28impl<'a> ConstRender<'a> { 28impl<'a> ConstRender<'a> {
29 fn new(ctx: RenderContext<'a>, const_: hir::Const) -> ConstRender<'a> { 29 fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> {
30 let ast_node = const_.source(ctx.db()).value; 30 let ast_node = const_.source(ctx.db())?.value;
31 ConstRender { ctx, const_, ast_node } 31 Some(ConstRender { ctx, const_, ast_node })
32 } 32 }
33 33
34 fn render(self) -> Option<CompletionItem> { 34 fn render(self) -> Option<CompletionItem> {
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index 316e05b52..081be14f4 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -14,9 +14,9 @@ pub(crate) fn render_fn<'a>(
14 import_to_add: Option<ImportEdit>, 14 import_to_add: Option<ImportEdit>,
15 local_name: Option<String>, 15 local_name: Option<String>,
16 fn_: hir::Function, 16 fn_: hir::Function,
17) -> CompletionItem { 17) -> Option<CompletionItem> {
18 let _p = profile::span("render_fn"); 18 let _p = profile::span("render_fn");
19 FunctionRender::new(ctx, local_name, fn_).render(import_to_add) 19 Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add))
20} 20}
21 21
22#[derive(Debug)] 22#[derive(Debug)]
@@ -32,11 +32,11 @@ impl<'a> FunctionRender<'a> {
32 ctx: RenderContext<'a>, 32 ctx: RenderContext<'a>,
33 local_name: Option<String>, 33 local_name: Option<String>,
34 fn_: hir::Function, 34 fn_: hir::Function,
35 ) -> FunctionRender<'a> { 35 ) -> Option<FunctionRender<'a>> {
36 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); 36 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string());
37 let ast_node = fn_.source(ctx.db()).value; 37 let ast_node = fn_.source(ctx.db())?.value;
38 38
39 FunctionRender { ctx, name, func: fn_, ast_node } 39 Some(FunctionRender { ctx, name, func: fn_, ast_node })
40 } 40 }
41 41
42 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { 42 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index dac79592f..6f4f9945c 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -39,20 +39,13 @@ impl<'a> MacroRender<'a> {
39 } 39 }
40 40
41 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { 41 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
42 // FIXME: Currently proc-macro do not have ast-node,
43 // such that it does not have source
44 // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
45 if self.macro_.is_proc_macro() {
46 return None;
47 }
48
49 let mut builder = 42 let mut builder =
50 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) 43 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
51 .kind(CompletionItemKind::Macro) 44 .kind(CompletionItemKind::Macro)
52 .set_documentation(self.docs.clone()) 45 .set_documentation(self.docs.clone())
53 .set_deprecated(self.ctx.is_deprecated(self.macro_)) 46 .set_deprecated(self.ctx.is_deprecated(self.macro_))
54 .add_import(import_to_add) 47 .add_import(import_to_add)
55 .detail(self.detail()); 48 .set_detail(self.detail());
56 49
57 let needs_bang = self.needs_bang(); 50 let needs_bang = self.needs_bang();
58 builder = match self.ctx.snippet_cap() { 51 builder = match self.ctx.snippet_cap() {
@@ -95,9 +88,9 @@ impl<'a> MacroRender<'a> {
95 format!("{}!", self.name) 88 format!("{}!", self.name)
96 } 89 }
97 90
98 fn detail(&self) -> String { 91 fn detail(&self) -> Option<String> {
99 let ast_node = self.macro_.source(self.ctx.db()).value; 92 let ast_node = self.macro_.source(self.ctx.db())?.value;
100 macro_label(&ast_node) 93 Some(macro_label(&ast_node))
101 } 94 }
102} 95}
103 96
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs
index 9605c7fa9..69b445b9c 100644
--- a/crates/completion/src/render/type_alias.rs
+++ b/crates/completion/src/render/type_alias.rs
@@ -15,7 +15,7 @@ pub(crate) fn render_type_alias<'a>(
15 ctx: RenderContext<'a>, 15 ctx: RenderContext<'a>,
16 type_alias: hir::TypeAlias, 16 type_alias: hir::TypeAlias,
17) -> Option<CompletionItem> { 17) -> Option<CompletionItem> {
18 TypeAliasRender::new(ctx, type_alias).render() 18 TypeAliasRender::new(ctx, type_alias)?.render()
19} 19}
20 20
21#[derive(Debug)] 21#[derive(Debug)]
@@ -26,9 +26,9 @@ struct TypeAliasRender<'a> {
26} 26}
27 27
28impl<'a> TypeAliasRender<'a> { 28impl<'a> TypeAliasRender<'a> {
29 fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> TypeAliasRender<'a> { 29 fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> {
30 let ast_node = type_alias.source(ctx.db()).value; 30 let ast_node = type_alias.source(ctx.db())?.value;
31 TypeAliasRender { ctx, type_alias, ast_node } 31 Some(TypeAliasRender { ctx, type_alias, ast_node })
32 } 32 }
33 33
34 fn render(self) -> Option<CompletionItem> { 34 fn render(self) -> Option<CompletionItem> {