Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/render.rs')
| -rw-r--r-- | crates/ide-completion/src/render.rs | 173 |
1 files changed, 107 insertions, 66 deletions
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 9c339a13e7..6571e67352 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -14,12 +14,16 @@ use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef}; use ide_db::{ helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, }; -use syntax::{SmolStr, SyntaxKind, TextRange}; +use syntax::{AstNode, SmolStr, SyntaxKind, TextRange}; use crate::{ - context::{PathCompletionCtx, PathKind}, + context::{DotAccess, PathCompletionCtx, PathKind, PatternContext}, item::{Builder, CompletionRelevanceTypeMatch}, - render::{function::render_fn, literal::render_variant_lit, macro_::render_macro}, + render::{ + function::render_fn, + literal::render_variant_lit, + macro_::{render_macro, render_macro_pat}, + }, CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, }; /// Interface for data and methods required for items rendering. @@ -106,6 +110,7 @@ impl<'a> RenderContext<'a> { pub(crate) fn render_field( ctx: RenderContext<'_>, + dot_access: &DotAccess, receiver: Option<hir::Name>, field: hir::Field, ty: &hir::Type, @@ -130,10 +135,10 @@ pub(crate) fn render_field( if is_keyword && !matches!(name.as_str(), "self" | "crate" | "super" | "Self") { item.insert_text(format!("r#{}", name)); } - if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { - // FIXME - // For now we don't properly calculate the edits for ref match - // completions on struct fields, so we've disabled them. See #8058. + if let Some(receiver) = &dot_access.receiver { + if let Some(ref_match) = compute_ref_match(ctx.completion, ty) { + item.ref_match(ref_match, receiver.syntax().text_range().start()); + } } item.build() } @@ -153,21 +158,29 @@ pub(crate) fn render_tuple_field( item.build() } +pub(crate) fn render_type_inference(ty_string: String, ctx: &CompletionContext) -> CompletionItem { + let mut builder = + CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string); + builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() }); + builder.build() +} + pub(crate) fn render_path_resolution( ctx: RenderContext<'_>, path_ctx: &PathCompletionCtx, local_name: hir::Name, resolution: ScopeDef, ) -> Builder { - render_resolution_(ctx, path_ctx, local_name, None, resolution) + render_resolution_path(ctx, path_ctx, local_name, None, resolution) } -pub(crate) fn render_resolution_simple( +pub(crate) fn render_pattern_resolution( ctx: RenderContext<'_>, + pattern_ctx: &PatternContext, local_name: hir::Name, resolution: ScopeDef, ) -> Builder { - render_resolution_simple_(ctx, local_name, None, resolution) + render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution) } pub(crate) fn render_resolution_with_import( @@ -176,23 +189,56 @@ pub(crate) fn render_resolution_with_import( import_edit: LocatedImport, ) -> Option<Builder> { let resolution = ScopeDef::from(import_edit.original_item); - let local_name = match resolution { + let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?; + + Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution)) +} + +pub(crate) fn render_resolution_with_import_pat( + ctx: RenderContext<'_>, + pattern_ctx: &PatternContext, + import_edit: LocatedImport, +) -> Option<Builder> { + let resolution = ScopeDef::from(import_edit.original_item); + let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?; + Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution)) +} + +fn scope_def_to_name( + resolution: ScopeDef, + ctx: &RenderContext, + import_edit: &LocatedImport, +) -> Option<hir::Name> { + Some(match resolution { ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), _ => item_name(ctx.db(), import_edit.original_item)?, - }; - Some(render_resolution_(ctx, path_ctx, local_name, Some(import_edit), resolution)) + }) } -pub(crate) fn render_type_inference(ty_string: String, ctx: &CompletionContext) -> CompletionItem { - let mut builder = - CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string); - builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() }); - builder.build() +fn render_resolution_pat( + ctx: RenderContext<'_>, + pattern_ctx: &PatternContext, + local_name: hir::Name, + import_to_add: Option<LocatedImport>, + resolution: ScopeDef, +) -> Builder { + let _p = profile::span("render_resolution"); + use hir::ModuleDef::*; + + match resolution { + ScopeDef::ModuleDef(Macro(mac)) => { + let ctx = ctx.import_to_add(import_to_add); + return render_macro_pat(ctx, pattern_ctx, local_name, mac); + } + _ => (), + } + + render_resolution_simple_(ctx, local_name, import_to_add, resolution) } -fn render_resolution_( +fn render_resolution_path( ctx: RenderContext<'_>, path_ctx: &PathCompletionCtx, local_name: hir::Name, @@ -221,19 +267,12 @@ fn render_resolution_( } _ => (), } - render_resolution_simple_type(ctx, path_ctx, local_name, import_to_add, resolution) -} -fn render_resolution_simple_type( - ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, - local_name: hir::Name, - import_to_add: Option<LocatedImport>, - resolution: ScopeDef, -) -> Builder { + let completion = ctx.completion; let cap = ctx.snippet_cap(); - let db = ctx.completion.db; - let config = ctx.completion.config; + let db = completion.db; + let config = completion.config; + let name = local_name.to_smol_str(); let mut item = render_resolution_simple_(ctx, local_name, import_to_add, resolution); // Add `<>` for generic types @@ -250,6 +289,7 @@ fn render_resolution_simple_type( } _ => false, }; + if has_non_default_type_params { cov_mark::hit!(inserts_angle_brackets_for_generics); item.lookup_by(name.clone()) @@ -259,6 +299,23 @@ fn render_resolution_simple_type( } } } + if let ScopeDef::Local(local) = resolution { + let ty = local.ty(db); + if !ty.is_unknown() { + item.detail(ty.display(db).to_string()); + } + + item.set_relevance(CompletionRelevance { + type_match: compute_type_match(completion, &ty), + exact_name_match: compute_exact_name_match(completion, &name), + is_local: true, + ..CompletionRelevance::default() + }); + + if let Some(ref_match) = compute_ref_match(completion, &ty) { + item.ref_match(ref_match, path_ctx.path.syntax().text_range().start()); + } + }; item } @@ -269,11 +326,25 @@ fn render_resolution_simple_( resolution: ScopeDef, ) -> Builder { let _p = profile::span("render_resolution"); - use hir::ModuleDef::*; let db = ctx.db(); let ctx = ctx.import_to_add(import_to_add); - let kind = match resolution { + let kind = res_to_kind(resolution); + + let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.to_smol_str()); + item.set_relevance(ctx.completion_relevance()) + .set_documentation(scope_def_docs(db, resolution)) + .set_deprecated(scope_def_is_deprecated(&ctx, resolution)); + + if let Some(import_to_add) = ctx.import_to_add { + item.add_import(import_to_add); + } + item +} + +fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { + use hir::ModuleDef::*; + match resolution { ScopeDef::Unknown => CompletionItemKind::UnresolvedReference, ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function), ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant), @@ -299,36 +370,7 @@ fn render_resolution_simple_( ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => { CompletionItemKind::SymbolKind(SymbolKind::SelfParam) } - }; - - let local_name = local_name.to_smol_str(); - let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone()); - item.set_relevance(ctx.completion_relevance()); - if let ScopeDef::Local(local) = resolution { - let ty = local.ty(db); - if !ty.is_unknown() { - item.detail(ty.display(db).to_string()); - } - - item.set_relevance(CompletionRelevance { - type_match: compute_type_match(ctx.completion, &ty), - exact_name_match: compute_exact_name_match(ctx.completion, &local_name), - is_local: true, - ..CompletionRelevance::default() - }); - - if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) { - item.ref_match(ref_match); - } - }; - - item.set_documentation(scope_def_docs(db, resolution)) - .set_deprecated(scope_def_is_deprecated(&ctx, resolution)); - - if let Some(import_to_add) = ctx.import_to_add { - item.add_import(import_to_add); } - item } fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> { @@ -455,7 +497,7 @@ mod tests { let relevance = display_relevance(it.relevance()); items.push(format!("{} {} {}\n", tag, it.label(), relevance)); - if let Some((mutability, relevance)) = it.ref_match() { + if let Some((mutability, _offset, relevance)) = it.ref_match() { let label = format!("&{}{}", mutability.as_keyword_for_ref(), it.label()); let relevance = display_relevance(relevance); @@ -1494,9 +1536,6 @@ impl Foo { fn baz(&self) -> u32 { 0 } } fn foo(f: Foo) { let _: &u32 = f.b$0 } "#, &[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)], - // FIXME - // Ideally we'd also suggest &f.bar and &f.baz() as exact - // type matches. See #8058. expect![[r#" [ CompletionItem { @@ -1507,6 +1546,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 } kind: Method, lookup: "baz", detail: "fn(&self) -> u32", + ref_match: "&@96", }, CompletionItem { label: "bar", @@ -1517,6 +1557,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 } Field, ), detail: "u32", + ref_match: "&@96", }, ] "#]], @@ -1525,7 +1566,6 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 } #[test] fn qualified_path_ref() { - // disabled right now because it doesn't render correctly, #8058 check_kinds( r#" struct S; @@ -1554,6 +1594,7 @@ fn main() { ), lookup: "foo", detail: "fn() -> S", + ref_match: "&@92", }, ] "#]], |