From 65a2be49539375502ca95c8da455f50f580df2e3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 24 Feb 2019 17:01:56 +0300 Subject: complete struct literals --- .../src/completion/complete_struct_literal.rs | 64 ++++++++++++++++++++++ .../src/completion/completion_context.rs | 6 ++ 2 files changed, 70 insertions(+) create mode 100644 crates/ra_ide_api/src/completion/complete_struct_literal.rs (limited to 'crates/ra_ide_api/src/completion') diff --git a/crates/ra_ide_api/src/completion/complete_struct_literal.rs b/crates/ra_ide_api/src/completion/complete_struct_literal.rs new file mode 100644 index 000000000..893056c2b --- /dev/null +++ b/crates/ra_ide_api/src/completion/complete_struct_literal.rs @@ -0,0 +1,64 @@ +use hir::{Ty, AdtDef, Docs}; + +use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionItemKind}; +use crate::completion::completion_item::CompletionKind; + +/// Complete dot accesses, i.e. fields or methods (currently only fields). +pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) { + let (function, struct_lit) = match (&ctx.function, ctx.struct_lit_syntax) { + (Some(function), Some(struct_lit)) => (function, struct_lit), + _ => return, + }; + let infer_result = function.infer(ctx.db); + let syntax_mapping = function.body_syntax_mapping(ctx.db); + let expr = match syntax_mapping.node_expr(struct_lit.into()) { + Some(expr) => expr, + None => return, + }; + let ty = infer_result[expr].clone(); + let (adt, substs) = match ty { + Ty::Adt { def_id, ref substs, .. } => (def_id, substs), + _ => return, + }; + match adt { + AdtDef::Struct(s) => { + for field in s.fields(ctx.db) { + CompletionItem::new( + CompletionKind::Reference, + ctx.source_range(), + field.name(ctx.db).to_string(), + ) + .kind(CompletionItemKind::Field) + .detail(field.ty(ctx.db).subst(substs).to_string()) + .set_documentation(field.docs(ctx.db)) + .add_to(acc); + } + } + + // TODO unions + AdtDef::Enum(_) => (), + }; +} + +#[cfg(test)] +mod tests { + use crate::completion::*; + use crate::completion::completion_item::check_completion; + + fn check_ref_completion(name: &str, code: &str) { + check_completion(name, code, CompletionKind::Reference); + } + + #[test] + fn test_struct_literal_field() { + check_ref_completion( + "test_struct_literal_field", + r" + struct A { the_field: u32 } + fn foo() { + A { the<|> } + } + ", + ); + } +} diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index b9f0abe19..d351be054 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -21,6 +21,7 @@ pub(crate) struct CompletionContext<'a> { pub(super) function: Option, pub(super) function_syntax: Option<&'a ast::FnDef>, pub(super) use_item_syntax: Option<&'a ast::UseItem>, + pub(super) struct_lit_syntax: Option<&'a ast::StructLit>, pub(super) is_param: bool, /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. pub(super) is_trivial_path: bool, @@ -55,6 +56,7 @@ impl<'a> CompletionContext<'a> { function: None, function_syntax: None, use_item_syntax: None, + struct_lit_syntax: None, is_param: false, is_trivial_path: false, path_prefix: None, @@ -108,6 +110,10 @@ impl<'a> CompletionContext<'a> { } fn classify_name_ref(&mut self, original_file: &'a SourceFile, name_ref: &ast::NameRef) { let name_range = name_ref.syntax().range(); + if name_ref.syntax().parent().and_then(ast::NamedField::cast).is_some() { + self.struct_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); + } + let top_node = name_ref.syntax().ancestors().take_while(|it| it.range() == name_range).last().unwrap(); -- cgit v1.2.3