From fc8a1cd8006b021541ff673ec7f37a0f4b7bef57 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sun, 1 Nov 2020 12:35:04 +0300 Subject: Introduce render module --- crates/completion/src/completions.rs | 260 ++--------------------------------- 1 file changed, 14 insertions(+), 246 deletions(-) (limited to 'crates/completion/src/completions.rs') diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index d5fb85b79..1ca5cf33d 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -14,14 +14,15 @@ pub(crate) mod macro_in_item_position; pub(crate) mod trait_impl; pub(crate) mod mod_; -use hir::{HasAttrs, HasSource, HirDisplay, ModPath, Mutability, ScopeDef, StructKind, Type}; -use itertools::Itertools; +use hir::{HasAttrs, HasSource, HirDisplay, ModPath, Mutability, ScopeDef, Type}; use syntax::{ast::NameOwner, display::*}; use test_utils::mark; use crate::{ - item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, - CompletionScore, RootDatabase, + item::Builder, + render::{EnumVariantRender, FunctionRender, MacroRender}, + CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionScore, + RootDatabase, }; /// Represents an in-progress set of completions being built. @@ -189,50 +190,14 @@ impl Completions { name: Option, macro_: hir::MacroDef, ) { - // FIXME: Currently proc-macro do not have ast-node, - // such that it does not have source - if macro_.is_proc_macro() { - return; - } - let name = match name { Some(it) => it, None => return, }; - let ast_node = macro_.source(ctx.db).value; - let detail = macro_label(&ast_node); - - let docs = macro_.docs(ctx.db); - - let mut builder = CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - &format!("{}!", name), - ) - .kind(CompletionItemKind::Macro) - .set_documentation(docs.clone()) - .set_deprecated(is_deprecated(macro_, ctx.db)) - .detail(detail); - - let needs_bang = ctx.use_item_syntax.is_none() && !ctx.is_macro_call; - builder = match ctx.config.snippet_cap { - Some(cap) if needs_bang => { - let docs = docs.as_ref().map_or("", |s| s.as_str()); - let (bra, ket) = guess_macro_braces(&name, docs); - builder - .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket)) - .label(format!("{}!{}…{}", name, bra, ket)) - .lookup_by(format!("{}!", name)) - } - None if needs_bang => builder.insert_text(format!("{}!", name)), - _ => { - mark::hit!(dont_insert_macro_call_parens_unncessary); - builder.insert_text(name) - } - }; - - self.add(builder.build()); + if let Some(item) = MacroRender::new(ctx.into(), name, macro_).render() { + self.add(item); + } } pub(crate) fn add_function( @@ -241,50 +206,9 @@ impl Completions { func: hir::Function, local_name: Option, ) { - fn add_arg(arg: &str, ty: &Type, ctx: &CompletionContext) -> String { - if let Some(derefed_ty) = ty.remove_ref() { - for (name, local) in ctx.locals.iter() { - if name == arg && local.ty(ctx.db) == derefed_ty { - return (if ty.is_mutable_reference() { "&mut " } else { "&" }).to_string() - + &arg.to_string(); - } - } - } - arg.to_string() - }; - let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); - let ast_node = func.source(ctx.db).value; - - let mut builder = - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) - .kind(if func.self_param(ctx.db).is_some() { - CompletionItemKind::Method - } else { - CompletionItemKind::Function - }) - .set_documentation(func.docs(ctx.db)) - .set_deprecated(is_deprecated(func, ctx.db)) - .detail(function_declaration(&ast_node)); - - let params_ty = func.params(ctx.db); - let params = ast_node - .param_list() - .into_iter() - .flat_map(|it| it.params()) - .zip(params_ty) - .flat_map(|(it, param_ty)| { - if let Some(pat) = it.pat() { - let name = pat.to_string(); - let arg = name.trim_start_matches("mut ").trim_start_matches('_'); - return Some(add_arg(arg, param_ty.ty(), ctx)); - } - None - }) - .collect(); + let item = FunctionRender::new(ctx.into(), local_name, func).render(); - builder = builder.add_call_parens(ctx, name, Params::Named(params)); - - self.add(builder.build()) + self.add(item) } pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { @@ -325,7 +249,8 @@ impl Completions { variant: hir::EnumVariant, path: ModPath, ) { - self.add_enum_variant_impl(ctx, variant, None, Some(path)) + let item = EnumVariantRender::new(ctx.into(), None, variant, Some(path)).render(); + self.add(item); } pub(crate) fn add_enum_variant( @@ -334,63 +259,8 @@ impl Completions { variant: hir::EnumVariant, local_name: Option, ) { - self.add_enum_variant_impl(ctx, variant, local_name, None) - } - - fn add_enum_variant_impl( - &mut self, - ctx: &CompletionContext, - variant: hir::EnumVariant, - local_name: Option, - path: Option, - ) { - let is_deprecated = is_deprecated(variant, ctx.db); - let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string()); - let (qualified_name, short_qualified_name) = match &path { - Some(path) => { - let full = path.to_string(); - let short = - path.segments[path.segments.len().saturating_sub(2)..].iter().join("::"); - (full, short) - } - None => (name.to_string(), name.to_string()), - }; - let detail_types = variant - .fields(ctx.db) - .into_iter() - .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); - let variant_kind = variant.kind(ctx.db); - let detail = match variant_kind { - StructKind::Tuple | StructKind::Unit => format!( - "({})", - detail_types.map(|(_, t)| t.display(ctx.db).to_string()).format(", ") - ), - StructKind::Record => format!( - "{{ {} }}", - detail_types - .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string())) - .format(", ") - ), - }; - let mut res = CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - qualified_name.clone(), - ) - .kind(CompletionItemKind::EnumVariant) - .set_documentation(variant.docs(ctx.db)) - .set_deprecated(is_deprecated) - .detail(detail); - - if variant_kind == StructKind::Tuple { - mark::hit!(inserts_parens_for_tuple_enums); - let params = Params::Anonymous(variant.fields(ctx.db).len()); - res = res.add_call_parens(ctx, short_qualified_name, params) - } else if path.is_some() { - res = res.lookup_by(short_qualified_name); - } - - res.add_to(self); + let item = EnumVariantRender::new(ctx.into(), local_name, variant, None).render(); + self.add(item); } } @@ -434,112 +304,10 @@ fn compute_score(ctx: &CompletionContext, ty: &Type, name: &str) -> Option), - Anonymous(usize), -} - -impl Params { - fn len(&self) -> usize { - match self { - Params::Named(xs) => xs.len(), - Params::Anonymous(len) => *len, - } - } - - fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl Builder { - fn add_call_parens(mut self, ctx: &CompletionContext, name: String, params: Params) -> Builder { - if !ctx.config.add_call_parenthesis { - return self; - } - if ctx.use_item_syntax.is_some() { - mark::hit!(no_parens_in_use_item); - return self; - } - if ctx.is_pattern_call { - mark::hit!(dont_duplicate_pattern_parens); - return self; - } - if ctx.is_call { - return self; - } - - // Don't add parentheses if the expected type is some function reference. - if let Some(ty) = &ctx.expected_type { - if ty.is_fn() { - mark::hit!(no_call_parens_if_fn_ptr_needed); - return self; - } - } - - let cap = match ctx.config.snippet_cap { - Some(it) => it, - None => return self, - }; - // If not an import, add parenthesis automatically. - mark::hit!(inserts_parens_for_function_calls); - - let (snippet, label) = if params.is_empty() { - (format!("{}()$0", name), format!("{}()", name)) - } else { - self = self.trigger_call_info(); - let snippet = match (ctx.config.add_call_argument_snippets, params) { - (true, Params::Named(params)) => { - let function_params_snippet = - params.iter().enumerate().format_with(", ", |(index, param_name), f| { - f(&format_args!("${{{}:{}}}", index + 1, param_name)) - }); - format!("{}({})$0", name, function_params_snippet) - } - _ => { - mark::hit!(suppress_arg_snippets); - format!("{}($0)", name) - } - }; - - (snippet, format!("{}(…)", name)) - }; - self.lookup_by(name).label(label).insert_snippet(cap, snippet) - } -} - fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool { node.attrs(db).by_key("deprecated").exists() } -fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) { - let mut votes = [0, 0, 0]; - for (idx, s) in docs.match_indices(¯o_name) { - let (before, after) = (&docs[..idx], &docs[idx + s.len()..]); - // Ensure to match the full word - if after.starts_with('!') - && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric()) - { - // It may have spaces before the braces like `foo! {}` - match after[1..].chars().find(|&c| !c.is_whitespace()) { - Some('{') => votes[0] += 1, - Some('[') => votes[1] += 1, - Some('(') => votes[2] += 1, - _ => {} - } - } - } - - // Insert a space before `{}`. - // We prefer the last one when some votes equal. - let (_vote, (bra, ket)) = votes - .iter() - .zip(&[(" {", "}"), ("[", "]"), ("(", ")")]) - .max_by_key(|&(&vote, _)| vote) - .unwrap(); - (*bra, *ket) -} - #[cfg(test)] mod tests { use std::cmp::Reverse; -- cgit v1.2.3 From 944ccf60758305a1b15224defe622cfca6939aaa Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sun, 1 Nov 2020 12:59:43 +0300 Subject: Add ConstRender --- crates/completion/src/completions.rs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'crates/completion/src/completions.rs') diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 1ca5cf33d..d8dc1b1c3 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -20,7 +20,7 @@ use test_utils::mark; use crate::{ item::Builder, - render::{EnumVariantRender, FunctionRender, MacroRender}, + render::{ConstRender, EnumVariantRender, FunctionRender, MacroRender}, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionScore, RootDatabase, }; @@ -194,7 +194,6 @@ impl Completions { Some(it) => it, None => return, }; - if let Some(item) = MacroRender::new(ctx.into(), name, macro_).render() { self.add(item); } @@ -207,24 +206,13 @@ impl Completions { local_name: Option, ) { let item = FunctionRender::new(ctx.into(), local_name, func).render(); - self.add(item) } pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { - let ast_node = constant.source(ctx.db).value; - let name = match ast_node.name() { - Some(name) => name, - _ => return, - }; - let detail = const_label(&ast_node); - - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) - .kind(CompletionItemKind::Const) - .set_documentation(constant.docs(ctx.db)) - .set_deprecated(is_deprecated(constant, ctx.db)) - .detail(detail) - .add_to(self); + if let Some(item) = ConstRender::new(ctx.into(), constant).render() { + self.add(item); + } } pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { -- cgit v1.2.3 From 15b16917fcd55068d9aba3d4b5d87763ec5deb69 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sun, 1 Nov 2020 13:10:02 +0300 Subject: Add TypeAliasRender --- crates/completion/src/completions.rs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'crates/completion/src/completions.rs') diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index d8dc1b1c3..434366b12 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -14,13 +14,12 @@ pub(crate) mod macro_in_item_position; pub(crate) mod trait_impl; pub(crate) mod mod_; -use hir::{HasAttrs, HasSource, HirDisplay, ModPath, Mutability, ScopeDef, Type}; -use syntax::{ast::NameOwner, display::*}; +use hir::{HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type}; use test_utils::mark; use crate::{ item::Builder, - render::{ConstRender, EnumVariantRender, FunctionRender, MacroRender}, + render::{ConstRender, EnumVariantRender, FunctionRender, MacroRender, TypeAliasRender}, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionScore, RootDatabase, }; @@ -216,19 +215,9 @@ impl Completions { } pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { - let type_def = type_alias.source(ctx.db).value; - let name = match type_def.name() { - Some(name) => name, - _ => return, - }; - let detail = type_label(&type_def); - - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) - .kind(CompletionItemKind::TypeAlias) - .set_documentation(type_alias.docs(ctx.db)) - .set_deprecated(is_deprecated(type_alias, ctx.db)) - .detail(detail) - .add_to(self); + if let Some(item) = TypeAliasRender::new(ctx.into(), type_alias).render() { + self.add(item) + } } pub(crate) fn add_qualified_enum_variant( -- cgit v1.2.3 From 97a504805d4b0cf8b48bc5052453b2b2f3298449 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sun, 1 Nov 2020 13:36:30 +0300 Subject: Move rendering tests to the render module --- crates/completion/src/completions.rs | 1082 +--------------------------------- 1 file changed, 8 insertions(+), 1074 deletions(-) (limited to 'crates/completion/src/completions.rs') diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 434366b12..b54771fcd 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -14,15 +14,9 @@ pub(crate) mod macro_in_item_position; pub(crate) mod trait_impl; pub(crate) mod mod_; -use hir::{HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type}; -use test_utils::mark; +use hir::{ModPath, ScopeDef, Type}; -use crate::{ - item::Builder, - render::{ConstRender, EnumVariantRender, FunctionRender, MacroRender, TypeAliasRender}, - CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionScore, - RootDatabase, -}; +use crate::{item::Builder, render::*, CompletionContext, CompletionItem}; /// Represents an in-progress set of completions being built. #[derive(Debug, Default)] @@ -58,27 +52,13 @@ impl Completions { } pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { - let is_deprecated = is_deprecated(field, ctx.db); - let name = field.name(ctx.db); - let mut item = - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) - .kind(CompletionItemKind::Field) - .detail(ty.display(ctx.db).to_string()) - .set_documentation(field.docs(ctx.db)) - .set_deprecated(is_deprecated); - - if let Some(score) = compute_score(ctx, &ty, &name.to_string()) { - item = item.set_score(score); - } - - item.add_to(self); + let item = Render::new(ctx.into()).add_field(field, ty); + self.add(item); } pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) - .kind(CompletionItemKind::Field) - .detail(ty.display(ctx.db).to_string()) - .add_to(self); + let item = Render::new(ctx.into()).add_tuple_field(field, ty); + self.add(item); } pub(crate) fn add_resolution( @@ -87,100 +67,9 @@ impl Completions { local_name: String, resolution: &ScopeDef, ) { - use hir::ModuleDef::*; - - let completion_kind = match resolution { - ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, - _ => CompletionKind::Reference, - }; - - let kind = match resolution { - ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, - ScopeDef::ModuleDef(Function(func)) => { - self.add_function(ctx, *func, Some(local_name)); - return; - } - ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, - // FIXME: add CompletionItemKind::Union - ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, - ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, - - ScopeDef::ModuleDef(EnumVariant(var)) => { - self.add_enum_variant(ctx, *var, Some(local_name)); - return; - } - ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, - ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, - ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, - ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, - ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, - ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, - ScopeDef::Local(..) => CompletionItemKind::Binding, - // (does this need its own kind?) - ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, - ScopeDef::MacroDef(mac) => { - self.add_macro(ctx, Some(local_name), *mac); - return; - } - ScopeDef::Unknown => { - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name) - .kind(CompletionItemKind::UnresolvedReference) - .add_to(self); - return; - } - }; - - let docs = match resolution { - ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db), - ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db), - ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db), - ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db), - ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db), - ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db), - ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db), - _ => None, - }; - - let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); - if let ScopeDef::Local(local) = resolution { - let ty = local.ty(ctx.db); - if !ty.is_unknown() { - item = item.detail(ty.display(ctx.db).to_string()); - } - }; - - let mut ref_match = None; - if let ScopeDef::Local(local) = resolution { - if let Some((active_name, active_type)) = ctx.active_name_and_type() { - let ty = local.ty(ctx.db); - if let Some(score) = - compute_score_from_active(&active_type, &active_name, &ty, &local_name) - { - item = item.set_score(score); - } - ref_match = refed_type_matches(&active_type, &active_name, &ty, &local_name); - } - } - - // Add `<>` for generic types - if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { - if let Some(cap) = ctx.config.snippet_cap { - let has_non_default_type_params = match resolution { - ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), - ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), - _ => false, - }; - if has_non_default_type_params { - mark::hit!(inserts_angle_brackets_for_generics); - item = item - .lookup_by(local_name.clone()) - .label(format!("{}<…>", local_name)) - .insert_snippet(cap, format!("{}<$0>", local_name)); - } - } + if let Some(item) = Render::new(ctx.into()).render_resolution(local_name, resolution) { + self.add(item); } - - item.kind(kind).set_documentation(docs).set_ref_match(ref_match).add_to(self) } pub(crate) fn add_macro( @@ -240,958 +129,3 @@ impl Completions { self.add(item); } } - -fn compute_score_from_active( - active_type: &Type, - active_name: &str, - ty: &Type, - name: &str, -) -> Option { - // Compute score - // For the same type - if active_type != ty { - return None; - } - - let mut res = CompletionScore::TypeMatch; - - // If same type + same name then go top position - if active_name == name { - res = CompletionScore::TypeAndNameMatch - } - - Some(res) -} -fn refed_type_matches( - active_type: &Type, - active_name: &str, - ty: &Type, - name: &str, -) -> Option<(Mutability, CompletionScore)> { - let derefed_active = active_type.remove_ref()?; - let score = compute_score_from_active(&derefed_active, &active_name, &ty, &name)?; - Some(( - if active_type.is_mutable_reference() { Mutability::Mut } else { Mutability::Shared }, - score, - )) -} - -fn compute_score(ctx: &CompletionContext, ty: &Type, name: &str) -> Option { - let (active_name, active_type) = ctx.active_name_and_type()?; - compute_score_from_active(&active_type, &active_name, ty, name) -} - -fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool { - node.attrs(db).by_key("deprecated").exists() -} - -#[cfg(test)] -mod tests { - use std::cmp::Reverse; - - use expect_test::{expect, Expect}; - use test_utils::mark; - - use crate::{ - test_utils::{check_edit, check_edit_with_config, do_completion, get_all_items}, - CompletionConfig, CompletionKind, CompletionScore, - }; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = do_completion(ra_fixture, CompletionKind::Reference); - expect.assert_debug_eq(&actual); - } - - fn check_scores(ra_fixture: &str, expect: Expect) { - fn display_score(score: Option) -> &'static str { - match score { - Some(CompletionScore::TypeMatch) => "[type]", - Some(CompletionScore::TypeAndNameMatch) => "[type+name]", - None => "[]".into(), - } - } - - let mut completions = get_all_items(CompletionConfig::default(), ra_fixture); - completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); - let actual = completions - .into_iter() - .filter(|it| it.completion_kind == CompletionKind::Reference) - .map(|it| { - let tag = it.kind().unwrap().tag(); - let score = display_score(it.score()); - format!("{} {} {}\n", tag, it.label(), score) - }) - .collect::(); - expect.assert_eq(&actual); - } - - #[test] - fn enum_detail_includes_record_fields() { - check( - r#" -enum Foo { Foo { x: i32, y: i32 } } - -fn main() { Foo::Fo<|> } -"#, - expect![[r#" - [ - CompletionItem { - label: "Foo", - source_range: 54..56, - delete: 54..56, - insert: "Foo", - kind: EnumVariant, - detail: "{ x: i32, y: i32 }", - }, - ] - "#]], - ); - } - - #[test] - fn enum_detail_doesnt_include_tuple_fields() { - check( - r#" -enum Foo { Foo (i32, i32) } - -fn main() { Foo::Fo<|> } -"#, - expect![[r#" - [ - CompletionItem { - label: "Foo(…)", - source_range: 46..48, - delete: 46..48, - insert: "Foo($0)", - kind: EnumVariant, - lookup: "Foo", - detail: "(i32, i32)", - trigger_call_info: true, - }, - ] - "#]], - ); - } - - #[test] - fn enum_detail_just_parentheses_for_unit() { - check( - r#" -enum Foo { Foo } - -fn main() { Foo::Fo<|> } -"#, - expect![[r#" - [ - CompletionItem { - label: "Foo", - source_range: 35..37, - delete: 35..37, - insert: "Foo", - kind: EnumVariant, - detail: "()", - }, - ] - "#]], - ); - } - - #[test] - fn lookup_enums_by_two_qualifiers() { - check( - r#" -mod m { - pub enum Spam { Foo, Bar(i32) } -} -fn main() { let _: m::Spam = S<|> } -"#, - expect![[r#" - [ - CompletionItem { - label: "Spam::Bar(…)", - source_range: 75..76, - delete: 75..76, - insert: "Spam::Bar($0)", - kind: EnumVariant, - lookup: "Spam::Bar", - detail: "(i32)", - trigger_call_info: true, - }, - CompletionItem { - label: "m", - source_range: 75..76, - delete: 75..76, - insert: "m", - kind: Module, - }, - CompletionItem { - label: "m::Spam::Foo", - source_range: 75..76, - delete: 75..76, - insert: "m::Spam::Foo", - kind: EnumVariant, - lookup: "Spam::Foo", - detail: "()", - }, - CompletionItem { - label: "main()", - source_range: 75..76, - delete: 75..76, - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "#]], - ) - } - - #[test] - fn sets_deprecated_flag_in_items() { - check( - r#" -#[deprecated] -fn something_deprecated() {} -#[deprecated(since = "1.0.0")] -fn something_else_deprecated() {} - -fn main() { som<|> } -"#, - expect![[r#" - [ - CompletionItem { - label: "main()", - source_range: 121..124, - delete: 121..124, - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - CompletionItem { - label: "something_deprecated()", - source_range: 121..124, - delete: 121..124, - insert: "something_deprecated()$0", - kind: Function, - lookup: "something_deprecated", - detail: "fn something_deprecated()", - deprecated: true, - }, - CompletionItem { - label: "something_else_deprecated()", - source_range: 121..124, - delete: 121..124, - insert: "something_else_deprecated()$0", - kind: Function, - lookup: "something_else_deprecated", - detail: "fn something_else_deprecated()", - deprecated: true, - }, - ] - "#]], - ); - - check( - r#" -struct A { #[deprecated] the_field: u32 } -fn foo() { A { the<|> } } -"#, - expect![[r#" - [ - CompletionItem { - label: "the_field", - source_range: 57..60, - delete: 57..60, - insert: "the_field", - kind: Field, - detail: "u32", - deprecated: true, - }, - ] - "#]], - ); - } - - #[test] - fn renders_docs() { - check( - r#" -struct S { - /// Field docs - foo: -} -impl S { - /// Method docs - fn bar(self) { self.<|> } -}"#, - expect![[r#" - [ - CompletionItem { - label: "bar()", - source_range: 94..94, - delete: 94..94, - insert: "bar()$0", - kind: Method, - lookup: "bar", - detail: "fn bar(self)", - documentation: Documentation( - "Method docs", - ), - }, - CompletionItem { - label: "foo", - source_range: 94..94, - delete: 94..94, - insert: "foo", - kind: Field, - detail: "{unknown}", - documentation: Documentation( - "Field docs", - ), - }, - ] - "#]], - ); - - check( - r#" -use self::my<|>; - -/// mod docs -mod my { } - -/// enum docs -enum E { - /// variant docs - V -} -use self::E::*; -"#, - expect![[r#" - [ - CompletionItem { - label: "E", - source_range: 10..12, - delete: 10..12, - insert: "E", - kind: Enum, - documentation: Documentation( - "enum docs", - ), - }, - CompletionItem { - label: "V", - source_range: 10..12, - delete: 10..12, - insert: "V", - kind: EnumVariant, - detail: "()", - documentation: Documentation( - "variant docs", - ), - }, - CompletionItem { - label: "my", - source_range: 10..12, - delete: 10..12, - insert: "my", - kind: Module, - documentation: Documentation( - "mod docs", - ), - }, - ] - "#]], - ) - } - - #[test] - fn dont_render_attrs() { - check( - r#" -struct S; -impl S { - #[inline] - fn the_method(&self) { } -} -fn foo(s: S) { s.<|> } -"#, - expect![[r#" - [ - CompletionItem { - label: "the_method()", - source_range: 81..81, - delete: 81..81, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn the_method(&self)", - }, - ] - "#]], - ) - } - - #[test] - fn inserts_parens_for_function_calls() { - mark::check!(inserts_parens_for_function_calls); - check_edit( - "no_args", - r#" -fn no_args() {} -fn main() { no_<|> } -"#, - r#" -fn no_args() {} -fn main() { no_args()$0 } -"#, - ); - - check_edit( - "with_args", - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_<|> } -"#, - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_args(${1:x}, ${2:y})$0 } -"#, - ); - - check_edit( - "foo", - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn bar(s: &S) { s.f<|> } -"#, - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn bar(s: &S) { s.foo()$0 } -"#, - ); - - check_edit( - "foo", - r#" -struct S {} -impl S { - fn foo(&self, x: i32) {} -} -fn bar(s: &S) { - s.f<|> -} -"#, - r#" -struct S {} -impl S { - fn foo(&self, x: i32) {} -} -fn bar(s: &S) { - s.foo(${1:x})$0 -} -"#, - ); - } - - #[test] - fn suppress_arg_snippets() { - mark::check!(suppress_arg_snippets); - check_edit_with_config( - CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() }, - "with_args", - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_<|> } -"#, - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_args($0) } -"#, - ); - } - - #[test] - fn strips_underscores_from_args() { - check_edit( - "foo", - r#" -fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} -fn main() { f<|> } -"#, - r#" -fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} -fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } -"#, - ); - } - - #[test] - fn insert_ref_when_matching_local_in_scope() { - check_edit( - "ref_arg", - r#" -struct Foo {} -fn ref_arg(x: &Foo) {} -fn main() { - let x = Foo {}; - ref_ar<|> -} -"#, - r#" -struct Foo {} -fn ref_arg(x: &Foo) {} -fn main() { - let x = Foo {}; - ref_arg(${1:&x})$0 -} -"#, - ); - } - - #[test] - fn insert_mut_ref_when_matching_local_in_scope() { - check_edit( - "ref_arg", - r#" -struct Foo {} -fn ref_arg(x: &mut Foo) {} -fn main() { - let x = Foo {}; - ref_ar<|> -} -"#, - r#" -struct Foo {} -fn ref_arg(x: &mut Foo) {} -fn main() { - let x = Foo {}; - ref_arg(${1:&mut x})$0 -} -"#, - ); - } - - #[test] - fn insert_ref_when_matching_local_in_scope_for_method() { - check_edit( - "apply_foo", - r#" -struct Foo {} -struct Bar {} -impl Bar { - fn apply_foo(&self, x: &Foo) {} -} - -fn main() { - let x = Foo {}; - let y = Bar {}; - y.<|> -} -"#, - r#" -struct Foo {} -struct Bar {} -impl Bar { - fn apply_foo(&self, x: &Foo) {} -} - -fn main() { - let x = Foo {}; - let y = Bar {}; - y.apply_foo(${1:&x})$0 -} -"#, - ); - } - - #[test] - fn trim_mut_keyword_in_func_completion() { - check_edit( - "take_mutably", - r#" -fn take_mutably(mut x: &i32) {} - -fn main() { - take_m<|> -} -"#, - r#" -fn take_mutably(mut x: &i32) {} - -fn main() { - take_mutably(${1:x})$0 -} -"#, - ); - } - - #[test] - fn inserts_parens_for_tuple_enums() { - mark::check!(inserts_parens_for_tuple_enums); - check_edit( - "Some", - r#" -enum Option { Some(T), None } -use Option::*; -fn main() -> Option { - Som<|> -} -"#, - r#" -enum Option { Some(T), None } -use Option::*; -fn main() -> Option { - Some($0) -} -"#, - ); - check_edit( - "Some", - r#" -enum Option { Some(T), None } -use Option::*; -fn main(value: Option) { - match value { - Som<|> - } -} -"#, - r#" -enum Option { Some(T), None } -use Option::*; -fn main(value: Option) { - match value { - Some($0) - } -} -"#, - ); - } - - #[test] - fn dont_duplicate_pattern_parens() { - mark::check!(dont_duplicate_pattern_parens); - check_edit( - "Var", - r#" -enum E { Var(i32) } -fn main() { - match E::Var(92) { - E::<|>(92) => (), - } -} -"#, - r#" -enum E { Var(i32) } -fn main() { - match E::Var(92) { - E::Var(92) => (), - } -} -"#, - ); - } - - #[test] - fn no_call_parens_if_fn_ptr_needed() { - mark::check!(no_call_parens_if_fn_ptr_needed); - check_edit( - "foo", - r#" -fn foo(foo: u8, bar: u8) {} -struct ManualVtable { f: fn(u8, u8) } - -fn main() -> ManualVtable { - ManualVtable { f: f<|> } -} -"#, - r#" -fn foo(foo: u8, bar: u8) {} -struct ManualVtable { f: fn(u8, u8) } - -fn main() -> ManualVtable { - ManualVtable { f: foo } -} -"#, - ); - } - - #[test] - fn no_parens_in_use_item() { - mark::check!(no_parens_in_use_item); - check_edit( - "foo", - r#" -mod m { pub fn foo() {} } -use crate::m::f<|>; -"#, - r#" -mod m { pub fn foo() {} } -use crate::m::foo; -"#, - ); - } - - #[test] - fn no_parens_in_call() { - check_edit( - "foo", - r#" -fn foo(x: i32) {} -fn main() { f<|>(); } -"#, - r#" -fn foo(x: i32) {} -fn main() { foo(); } -"#, - ); - check_edit( - "foo", - r#" -struct Foo; -impl Foo { fn foo(&self){} } -fn f(foo: &Foo) { foo.f<|>(); } -"#, - r#" -struct Foo; -impl Foo { fn foo(&self){} } -fn f(foo: &Foo) { foo.foo(); } -"#, - ); - } - - #[test] - fn inserts_angle_brackets_for_generics() { - mark::check!(inserts_angle_brackets_for_generics); - check_edit( - "Vec", - r#" -struct Vec {} -fn foo(xs: Ve<|>) -"#, - r#" -struct Vec {} -fn foo(xs: Vec<$0>) -"#, - ); - check_edit( - "Vec", - r#" -type Vec = (T,); -fn foo(xs: Ve<|>) -"#, - r#" -type Vec = (T,); -fn foo(xs: Vec<$0>) -"#, - ); - check_edit( - "Vec", - r#" -struct Vec {} -fn foo(xs: Ve<|>) -"#, - r#" -struct Vec {} -fn foo(xs: Vec) -"#, - ); - check_edit( - "Vec", - r#" -struct Vec {} -fn foo(xs: Ve<|>) -"#, - r#" -struct Vec {} -fn foo(xs: Vec) -"#, - ); - } - - #[test] - fn dont_insert_macro_call_parens_unncessary() { - mark::check!(dont_insert_macro_call_parens_unncessary); - check_edit( - "frobnicate!", - r#" -//- /main.rs crate:main deps:foo -use foo::<|>; -//- /foo/lib.rs crate:foo -#[macro_export] -macro_rules frobnicate { () => () } -"#, - r#" -use foo::frobnicate; -"#, - ); - - check_edit( - "frobnicate!", - r#" -macro_rules frobnicate { () => () } -fn main() { frob<|>!(); } -"#, - r#" -macro_rules frobnicate { () => () } -fn main() { frobnicate!(); } -"#, - ); - } - - #[test] - fn active_param_score() { - mark::check!(active_param_type_match); - check_scores( - r#" -struct S { foo: i64, bar: u32, baz: u32 } -fn test(bar: u32) { } -fn foo(s: S) { test(s.<|>) } -"#, - expect![[r#" - fd bar [type+name] - fd baz [type] - fd foo [] - "#]], - ); - } - - #[test] - fn record_field_scores() { - mark::check!(record_field_type_match); - check_scores( - r#" -struct A { foo: i64, bar: u32, baz: u32 } -struct B { x: (), y: f32, bar: u32 } -fn foo(a: A) { B { bar: a.<|> }; } -"#, - expect![[r#" - fd bar [type+name] - fd baz [type] - fd foo [] - "#]], - ) - } - - #[test] - fn record_field_and_call_scores() { - check_scores( - r#" -struct A { foo: i64, bar: u32, baz: u32 } -struct B { x: (), y: f32, bar: u32 } -fn f(foo: i64) { } -fn foo(a: A) { B { bar: f(a.<|>) }; } -"#, - expect![[r#" - fd foo [type+name] - fd bar [] - fd baz [] - "#]], - ); - check_scores( - r#" -struct A { foo: i64, bar: u32, baz: u32 } -struct B { x: (), y: f32, bar: u32 } -fn f(foo: i64) { } -fn foo(a: A) { f(B { bar: a.<|> }); } -"#, - expect![[r#" - fd bar [type+name] - fd baz [type] - fd foo [] - "#]], - ); - } - - #[test] - fn prioritize_exact_ref_match() { - check_scores( - r#" -struct WorldSnapshot { _f: () }; -fn go(world: &WorldSnapshot) { go(w<|>) } -"#, - expect![[r#" - bn world [type+name] - st WorldSnapshot [] - fn go(…) [] - "#]], - ); - } - - #[test] - fn too_many_arguments() { - check_scores( - r#" -struct Foo; -fn f(foo: &Foo) { f(foo, w<|>) } -"#, - expect![[r#" - st Foo [] - fn f(…) [] - bn foo [] - "#]], - ); - } - - #[test] - fn guesses_macro_braces() { - check_edit( - "vec!", - r#" -/// Creates a [`Vec`] containing the arguments. -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// ``` -macro_rules! vec { () => {} } - -fn fn main() { v<|> } -"#, - r#" -/// Creates a [`Vec`] containing the arguments. -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// ``` -macro_rules! vec { () => {} } - -fn fn main() { vec![$0] } -"#, - ); - - check_edit( - "foo!", - r#" -/// Foo -/// -/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, -/// call as `let _=foo! { hello world };` -macro_rules! foo { () => {} } -fn main() { <|> } -"#, - r#" -/// Foo -/// -/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, -/// call as `let _=foo! { hello world };` -macro_rules! foo { () => {} } -fn main() { foo! {$0} } -"#, - ) - } -} -- cgit v1.2.3 From caf0fa20a7d895612ceee1948d6a9895e53bee4a Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Tue, 3 Nov 2020 10:17:59 +0300 Subject: Provide only explicit constructor for RenderContext --- crates/completion/src/completions.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'crates/completion/src/completions.rs') diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index b54771fcd..d59f5ca05 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -52,12 +52,12 @@ impl Completions { } pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { - let item = Render::new(ctx.into()).add_field(field, ty); + let item = Render::new(RenderContext::new(ctx)).add_field(field, ty); self.add(item); } pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { - let item = Render::new(ctx.into()).add_tuple_field(field, ty); + let item = Render::new(RenderContext::new(ctx)).add_tuple_field(field, ty); self.add(item); } @@ -67,7 +67,9 @@ impl Completions { local_name: String, resolution: &ScopeDef, ) { - if let Some(item) = Render::new(ctx.into()).render_resolution(local_name, resolution) { + if let Some(item) = + Render::new(RenderContext::new(ctx)).render_resolution(local_name, resolution) + { self.add(item); } } @@ -82,7 +84,7 @@ impl Completions { Some(it) => it, None => return, }; - if let Some(item) = MacroRender::new(ctx.into(), name, macro_).render() { + if let Some(item) = MacroRender::new(RenderContext::new(ctx), name, macro_).render() { self.add(item); } } @@ -93,18 +95,18 @@ impl Completions { func: hir::Function, local_name: Option, ) { - let item = FunctionRender::new(ctx.into(), local_name, func).render(); + let item = FunctionRender::new(RenderContext::new(ctx), local_name, func).render(); self.add(item) } pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { - if let Some(item) = ConstRender::new(ctx.into(), constant).render() { + if let Some(item) = ConstRender::new(RenderContext::new(ctx), constant).render() { self.add(item); } } pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { - if let Some(item) = TypeAliasRender::new(ctx.into(), type_alias).render() { + if let Some(item) = TypeAliasRender::new(RenderContext::new(ctx), type_alias).render() { self.add(item) } } @@ -115,7 +117,8 @@ impl Completions { variant: hir::EnumVariant, path: ModPath, ) { - let item = EnumVariantRender::new(ctx.into(), None, variant, Some(path)).render(); + let item = + EnumVariantRender::new(RenderContext::new(ctx), None, variant, Some(path)).render(); self.add(item); } @@ -125,7 +128,8 @@ impl Completions { variant: hir::EnumVariant, local_name: Option, ) { - let item = EnumVariantRender::new(ctx.into(), local_name, variant, None).render(); + let item = + EnumVariantRender::new(RenderContext::new(ctx), local_name, variant, None).render(); self.add(item); } } -- cgit v1.2.3 From 4d333ebb6372c135e5a723da899528cc22d07faa Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Tue, 3 Nov 2020 10:33:13 +0300 Subject: Get rid of do-er antipattern --- crates/completion/src/completions.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'crates/completion/src/completions.rs') diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index d59f5ca05..162d567d9 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -52,12 +52,12 @@ impl Completions { } pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { - let item = Render::new(RenderContext::new(ctx)).add_field(field, ty); + let item = render_field(RenderContext::new(ctx), field, ty); self.add(item); } pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { - let item = Render::new(RenderContext::new(ctx)).add_tuple_field(field, ty); + let item = render_tuple_field(RenderContext::new(ctx), field, ty); self.add(item); } @@ -67,9 +67,7 @@ impl Completions { local_name: String, resolution: &ScopeDef, ) { - if let Some(item) = - Render::new(RenderContext::new(ctx)).render_resolution(local_name, resolution) - { + if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { self.add(item); } } @@ -84,7 +82,7 @@ impl Completions { Some(it) => it, None => return, }; - if let Some(item) = MacroRender::new(RenderContext::new(ctx), name, macro_).render() { + if let Some(item) = render_macro(RenderContext::new(ctx), name, macro_) { self.add(item); } } @@ -95,18 +93,18 @@ impl Completions { func: hir::Function, local_name: Option, ) { - let item = FunctionRender::new(RenderContext::new(ctx), local_name, func).render(); + let item = render_fn(RenderContext::new(ctx), local_name, func); self.add(item) } pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { - if let Some(item) = ConstRender::new(RenderContext::new(ctx), constant).render() { + if let Some(item) = render_const(RenderContext::new(ctx), constant) { self.add(item); } } pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { - if let Some(item) = TypeAliasRender::new(RenderContext::new(ctx), type_alias).render() { + if let Some(item) = render_type_alias(RenderContext::new(ctx), type_alias) { self.add(item) } } @@ -117,8 +115,7 @@ impl Completions { variant: hir::EnumVariant, path: ModPath, ) { - let item = - EnumVariantRender::new(RenderContext::new(ctx), None, variant, Some(path)).render(); + let item = render_enum_variant(RenderContext::new(ctx), None, variant, Some(path)); self.add(item); } @@ -128,8 +125,7 @@ impl Completions { variant: hir::EnumVariant, local_name: Option, ) { - let item = - EnumVariantRender::new(RenderContext::new(ctx), local_name, variant, None).render(); + let item = render_enum_variant(RenderContext::new(ctx), local_name, variant, None); self.add(item); } } -- cgit v1.2.3 From 8efe43245bc64ed27f88c333541b2cb7af2ce44c Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Tue, 3 Nov 2020 10:36:01 +0300 Subject: Remove intra-crate facade from completions --- crates/completion/src/completions.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'crates/completion/src/completions.rs') diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 162d567d9..75dbb1a23 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -16,7 +16,15 @@ pub(crate) mod mod_; use hir::{ModPath, ScopeDef, Type}; -use crate::{item::Builder, render::*, CompletionContext, CompletionItem}; +use crate::{ + item::Builder, + render::{ + const_::render_const, enum_variant::render_enum_variant, function::render_fn, + macro_::render_macro, render_field, render_resolution, render_tuple_field, + type_alias::render_type_alias, RenderContext, + }, + CompletionContext, CompletionItem, +}; /// Represents an in-progress set of completions being built. #[derive(Debug, Default)] -- cgit v1.2.3