mirror of
https://github.com/rust-lang/rust
synced 2024-10-04 07:40:48 +00:00
Merge #11086
11086: internal: Simplify completion rendering r=Veykril a=Veykril Removes all the helper render structs in favor of simple functions, making things a lot easier to oversee(imho) bors r+ Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
22adcfde03
|
@ -3024,7 +3024,7 @@ pub fn return_type(&self) -> Type {
|
|||
}
|
||||
|
||||
/// For IDE only
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ScopeDef {
|
||||
ModuleDef(ModuleDef),
|
||||
MacroDef(MacroDef),
|
||||
|
|
|
@ -84,7 +84,7 @@ pub(crate) fn add_resolution(
|
|||
&mut self,
|
||||
ctx: &CompletionContext,
|
||||
local_name: hir::Name,
|
||||
resolution: &hir::ScopeDef,
|
||||
resolution: hir::ScopeDef,
|
||||
) {
|
||||
if ctx.is_scope_def_hidden(resolution) {
|
||||
cov_mark::hit!(qualified_path_doc_hidden);
|
||||
|
@ -115,7 +115,7 @@ pub(crate) fn add_function(
|
|||
if !ctx.is_visible(&func) {
|
||||
return;
|
||||
}
|
||||
self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func));
|
||||
self.add(render_fn(RenderContext::new(ctx), None, local_name, func));
|
||||
}
|
||||
|
||||
pub(crate) fn add_method(
|
||||
|
@ -128,7 +128,7 @@ pub(crate) fn add_method(
|
|||
if !ctx.is_visible(&func) {
|
||||
return;
|
||||
}
|
||||
self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
|
||||
self.add(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
|
||||
}
|
||||
|
||||
pub(crate) fn add_const(&mut self, ctx: &CompletionContext, konst: hir::Const) {
|
||||
|
|
|
@ -35,7 +35,7 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext)
|
|||
ctx.scope.process_all_names(&mut |name, res| {
|
||||
if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
|
||||
if param_lifetime != Some(&*name.to_smol_str()) {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -51,7 +51,7 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
|
|||
}
|
||||
ctx.scope.process_all_names(&mut |name, res| {
|
||||
if let ScopeDef::Label(_) = res {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
|
|||
_ => false,
|
||||
};
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
|||
}
|
||||
}
|
||||
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
|
||||
acc.add_resolution(ctx, name, &def);
|
||||
acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
|||
.next()
|
||||
{
|
||||
if let Some(name) = next.name(ctx.db) {
|
||||
acc.add_resolution(ctx, name, &ScopeDef::ModuleDef(next.into()));
|
||||
acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
|||
_ => false,
|
||||
};
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, &def);
|
||||
acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
|||
};
|
||||
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, &def);
|
||||
acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
|||
cov_mark::hit!(unqualified_path_only_modules_in_import);
|
||||
ctx.process_all_names(&mut |name, res| {
|
||||
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -43,7 +43,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
|||
_ => false,
|
||||
};
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
return;
|
||||
|
@ -61,7 +61,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
|||
}
|
||||
}
|
||||
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
return;
|
||||
|
@ -76,7 +76,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
|||
_ => false,
|
||||
};
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
return;
|
||||
|
@ -134,7 +134,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
|||
_ => true,
|
||||
};
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, &res);
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -278,7 +278,7 @@ pub(crate) fn is_visible<I>(&self, item: &I) -> bool
|
|||
self.is_visible_impl(&item.visibility(self.db), &item.attrs(self.db), item.krate(self.db))
|
||||
}
|
||||
|
||||
pub(crate) fn is_scope_def_hidden(&self, scope_def: &ScopeDef) -> bool {
|
||||
pub(crate) fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
|
||||
if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) {
|
||||
return self.is_doc_hidden(&attrs, krate);
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ pub(crate) fn is_immediately_after_macro_bang(&self) -> bool {
|
|||
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
|
||||
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
|
||||
self.scope.process_all_names(&mut |name, def| {
|
||||
if self.is_scope_def_hidden(&def) {
|
||||
if self.is_scope_def_hidden(def) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -367,7 +367,7 @@ pub(super) fn new(
|
|||
parse.reparse(&edit).tree()
|
||||
};
|
||||
let fake_ident_token =
|
||||
file_with_fake_ident.syntax().token_at_offset(offset).right_biased().unwrap();
|
||||
file_with_fake_ident.syntax().token_at_offset(offset).right_biased()?;
|
||||
|
||||
let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
|
||||
let token = sema.descend_into_macros_single(original_token.clone());
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
mod builder_ext;
|
||||
|
||||
use hir::{AsAssocItem, HasAttrs, HirDisplay};
|
||||
use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
|
||||
use ide_db::{
|
||||
helpers::{item_name, SnippetCap},
|
||||
RootDatabase, SymbolKind,
|
||||
|
@ -47,8 +47,8 @@ fn source_range(&self) -> TextRange {
|
|||
self.completion.source_range()
|
||||
}
|
||||
|
||||
fn is_deprecated(&self, node: impl HasAttrs) -> bool {
|
||||
let attrs = node.attrs(self.db());
|
||||
fn is_deprecated(&self, def: impl HasAttrs) -> bool {
|
||||
let attrs = def.attrs(self.db());
|
||||
attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,8 @@ fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
|
||||
node.docs(self.db())
|
||||
fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
|
||||
def.docs(self.db())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ pub(crate) fn render_tuple_field(
|
|||
pub(crate) fn render_resolution(
|
||||
ctx: RenderContext<'_>,
|
||||
local_name: hir::Name,
|
||||
resolution: &hir::ScopeDef,
|
||||
resolution: ScopeDef,
|
||||
) -> Option<CompletionItem> {
|
||||
render_resolution_(ctx, local_name, None, resolution)
|
||||
}
|
||||
|
@ -137,65 +137,36 @@ pub(crate) fn render_resolution_with_import(
|
|||
ctx: RenderContext<'_>,
|
||||
import_edit: ImportEdit,
|
||||
) -> Option<CompletionItem> {
|
||||
let resolution = hir::ScopeDef::from(import_edit.import.original_item);
|
||||
let resolution = ScopeDef::from(import_edit.import.original_item);
|
||||
let local_name = match resolution {
|
||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
|
||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
|
||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
|
||||
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.import.original_item)?,
|
||||
};
|
||||
render_resolution_(ctx, local_name, Some(import_edit), &resolution)
|
||||
render_resolution_(ctx, local_name, Some(import_edit), resolution)
|
||||
}
|
||||
|
||||
fn render_resolution_(
|
||||
ctx: RenderContext<'_>,
|
||||
local_name: hir::Name,
|
||||
import_to_add: Option<ImportEdit>,
|
||||
resolution: &hir::ScopeDef,
|
||||
resolution: ScopeDef,
|
||||
) -> Option<CompletionItem> {
|
||||
let _p = profile::span("render_resolution");
|
||||
use hir::ModuleDef::*;
|
||||
|
||||
let kind = match resolution {
|
||||
hir::ScopeDef::ModuleDef(Function(func)) => {
|
||||
return render_fn(ctx, import_to_add, Some(local_name), *func);
|
||||
}
|
||||
hir::ScopeDef::ModuleDef(Variant(_)) if ctx.completion.pattern_ctx.is_some() => {
|
||||
CompletionItemKind::SymbolKind(SymbolKind::Variant)
|
||||
}
|
||||
hir::ScopeDef::ModuleDef(Variant(var)) => {
|
||||
let item = render_variant(ctx, import_to_add, Some(local_name), *var, None);
|
||||
return Some(item);
|
||||
}
|
||||
hir::ScopeDef::MacroDef(mac) => {
|
||||
let item = render_macro(ctx, import_to_add, local_name, *mac);
|
||||
return item;
|
||||
}
|
||||
let db = ctx.db();
|
||||
|
||||
hir::ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
|
||||
hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
|
||||
hir::Adt::Struct(_) => SymbolKind::Struct,
|
||||
hir::Adt::Union(_) => SymbolKind::Union,
|
||||
hir::Adt::Enum(_) => SymbolKind::Enum,
|
||||
}),
|
||||
hir::ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
|
||||
hir::ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
|
||||
hir::ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
|
||||
hir::ScopeDef::ModuleDef(TypeAlias(..)) => {
|
||||
CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
|
||||
let kind = match resolution {
|
||||
ScopeDef::ModuleDef(Function(func)) => {
|
||||
return Some(render_fn(ctx, import_to_add, Some(local_name), func));
|
||||
}
|
||||
hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
|
||||
hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
|
||||
hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
|
||||
hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
|
||||
hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
|
||||
}),
|
||||
hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
|
||||
hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
|
||||
hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => {
|
||||
CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
|
||||
ScopeDef::ModuleDef(Variant(var)) if ctx.completion.pattern_ctx.is_none() => {
|
||||
return Some(render_variant(ctx, import_to_add, Some(local_name), var, None));
|
||||
}
|
||||
hir::ScopeDef::Unknown => {
|
||||
ScopeDef::MacroDef(mac) => return render_macro(ctx, import_to_add, local_name, mac),
|
||||
ScopeDef::Unknown => {
|
||||
let mut item = CompletionItem::new(
|
||||
CompletionItemKind::UnresolvedReference,
|
||||
ctx.source_range(),
|
||||
|
@ -206,14 +177,37 @@ fn render_resolution_(
|
|||
}
|
||||
return Some(item.build());
|
||||
}
|
||||
|
||||
ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
|
||||
ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
|
||||
ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
|
||||
hir::Adt::Struct(_) => SymbolKind::Struct,
|
||||
hir::Adt::Union(_) => SymbolKind::Union,
|
||||
hir::Adt::Enum(_) => SymbolKind::Enum,
|
||||
}),
|
||||
ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
|
||||
ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
|
||||
ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
|
||||
ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias),
|
||||
ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
|
||||
ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
|
||||
hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
|
||||
hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
|
||||
hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
|
||||
}),
|
||||
ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
|
||||
ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
|
||||
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());
|
||||
if let hir::ScopeDef::Local(local) = resolution {
|
||||
let ty = local.ty(ctx.db());
|
||||
if let ScopeDef::Local(local) = resolution {
|
||||
let ty = local.ty(db);
|
||||
if !ty.is_unknown() {
|
||||
item.detail(ty.display(ctx.db()).to_string());
|
||||
item.detail(ty.display(db).to_string());
|
||||
}
|
||||
|
||||
item.set_relevance(CompletionRelevance {
|
||||
|
@ -229,15 +223,15 @@ fn render_resolution_(
|
|||
};
|
||||
|
||||
// Add `<>` for generic types
|
||||
if matches!(
|
||||
let type_path_no_ty_args = matches!(
|
||||
ctx.completion.path_context,
|
||||
Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
|
||||
) && ctx.completion.config.add_call_parenthesis
|
||||
{
|
||||
) && ctx.completion.config.add_call_parenthesis;
|
||||
if type_path_no_ty_args {
|
||||
if let Some(cap) = ctx.snippet_cap() {
|
||||
let has_non_default_type_params = match resolution {
|
||||
hir::ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()),
|
||||
hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()),
|
||||
ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(db),
|
||||
ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(db),
|
||||
_ => false,
|
||||
};
|
||||
if has_non_default_type_params {
|
||||
|
@ -248,7 +242,7 @@ fn render_resolution_(
|
|||
}
|
||||
}
|
||||
}
|
||||
item.set_documentation(scope_def_docs(ctx.db(), resolution))
|
||||
item.set_documentation(scope_def_docs(db, resolution))
|
||||
.set_deprecated(scope_def_is_deprecated(&ctx, resolution));
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
|
@ -257,26 +251,26 @@ fn render_resolution_(
|
|||
Some(item.build())
|
||||
}
|
||||
|
||||
fn scope_def_docs(db: &RootDatabase, resolution: &hir::ScopeDef) -> Option<hir::Documentation> {
|
||||
fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
|
||||
use hir::ModuleDef::*;
|
||||
match resolution {
|
||||
hir::ScopeDef::ModuleDef(Module(it)) => it.docs(db),
|
||||
hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
|
||||
hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
|
||||
hir::ScopeDef::ModuleDef(Const(it)) => it.docs(db),
|
||||
hir::ScopeDef::ModuleDef(Static(it)) => it.docs(db),
|
||||
hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
|
||||
hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
|
||||
ScopeDef::ModuleDef(Module(it)) => it.docs(db),
|
||||
ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
|
||||
ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
|
||||
ScopeDef::ModuleDef(Const(it)) => it.docs(db),
|
||||
ScopeDef::ModuleDef(Static(it)) => it.docs(db),
|
||||
ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
|
||||
ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: &hir::ScopeDef) -> bool {
|
||||
fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> bool {
|
||||
match resolution {
|
||||
hir::ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(*it),
|
||||
hir::ScopeDef::MacroDef(it) => ctx.is_deprecated(*it),
|
||||
hir::ScopeDef::GenericParam(it) => ctx.is_deprecated(*it),
|
||||
hir::ScopeDef::AdtSelfType(it) => ctx.is_deprecated(*it),
|
||||
ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(it),
|
||||
ScopeDef::MacroDef(it) => ctx.is_deprecated(it),
|
||||
ScopeDef::GenericParam(it) => ctx.is_deprecated(it),
|
||||
ScopeDef::AdtSelfType(it) => ctx.is_deprecated(it),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,53 +2,32 @@
|
|||
|
||||
use hir::{AsAssocItem, HasSource};
|
||||
use ide_db::SymbolKind;
|
||||
use syntax::{ast::Const, display::const_label};
|
||||
use syntax::display::const_label;
|
||||
|
||||
use crate::{item::CompletionItem, render::RenderContext};
|
||||
|
||||
pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
|
||||
let _p = profile::span("render_const");
|
||||
ConstRender::new(ctx, const_)?.render()
|
||||
render(ctx, const_)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ConstRender<'a> {
|
||||
ctx: RenderContext<'a>,
|
||||
const_: hir::Const,
|
||||
ast_node: Const,
|
||||
}
|
||||
fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
|
||||
let db = ctx.db();
|
||||
let name = const_.name(db)?.to_smol_str();
|
||||
// FIXME: This is parsing files!
|
||||
let detail = const_label(&const_.source(db)?.value);
|
||||
|
||||
impl<'a> ConstRender<'a> {
|
||||
fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> {
|
||||
let ast_node = const_.source(ctx.db())?.value;
|
||||
Some(ConstRender { ctx, const_, ast_node })
|
||||
}
|
||||
let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone());
|
||||
item.set_documentation(ctx.docs(const_))
|
||||
.set_deprecated(ctx.is_deprecated(const_) || ctx.is_deprecated_assoc_item(const_))
|
||||
.detail(detail);
|
||||
|
||||
fn render(self) -> Option<CompletionItem> {
|
||||
let name = self.const_.name(self.ctx.db())?.to_smol_str();
|
||||
let detail = self.detail();
|
||||
|
||||
let mut item =
|
||||
CompletionItem::new(SymbolKind::Const, self.ctx.source_range(), name.clone());
|
||||
item.set_documentation(self.ctx.docs(self.const_))
|
||||
.set_deprecated(
|
||||
self.ctx.is_deprecated(self.const_)
|
||||
|| self.ctx.is_deprecated_assoc_item(self.const_),
|
||||
)
|
||||
.detail(detail);
|
||||
|
||||
let db = self.ctx.db();
|
||||
if let Some(actm) = self.const_.as_assoc_item(db) {
|
||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||
item.trait_name(trt.name(db).to_smol_str());
|
||||
item.insert_text(name);
|
||||
}
|
||||
if let Some(actm) = const_.as_assoc_item(db) {
|
||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||
item.trait_name(trt.name(db).to_smol_str());
|
||||
item.insert_text(name);
|
||||
}
|
||||
|
||||
Some(item.build())
|
||||
}
|
||||
|
||||
fn detail(&self) -> String {
|
||||
const_label(&self.ast_node)
|
||||
}
|
||||
Some(item.build())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Renderer for `enum` variants.
|
||||
|
||||
use std::{iter, mem};
|
||||
use std::iter;
|
||||
|
||||
use hir::{HasAttrs, HirDisplay};
|
||||
use hir::{db::HirDatabase, HasAttrs, HirDisplay, StructKind};
|
||||
use ide_db::SymbolKind;
|
||||
use stdx::format_to;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
item::{CompletionItem, ImportEdit},
|
||||
|
@ -20,116 +20,86 @@ pub(crate) fn render_variant(
|
|||
path: Option<hir::ModPath>,
|
||||
) -> CompletionItem {
|
||||
let _p = profile::span("render_enum_variant");
|
||||
EnumRender::new(ctx, local_name, variant, path).render(import_to_add)
|
||||
render(ctx, local_name, variant, path, import_to_add)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EnumRender<'a> {
|
||||
ctx: RenderContext<'a>,
|
||||
fn render(
|
||||
ctx @ RenderContext { completion }: RenderContext<'_>,
|
||||
local_name: Option<hir::Name>,
|
||||
variant: hir::Variant,
|
||||
path: Option<hir::ModPath>,
|
||||
qualified_name: hir::ModPath,
|
||||
short_qualified_name: hir::ModPath,
|
||||
variant_kind: hir::StructKind,
|
||||
import_to_add: Option<ImportEdit>,
|
||||
) -> CompletionItem {
|
||||
let db = completion.db;
|
||||
let name = local_name.unwrap_or_else(|| variant.name(db));
|
||||
let variant_kind = variant.kind(db);
|
||||
|
||||
let (qualified_name, short_qualified_name, qualified) = match path {
|
||||
Some(path) => {
|
||||
let short = hir::ModPath::from_segments(
|
||||
hir::PathKind::Plain,
|
||||
path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(),
|
||||
);
|
||||
(path, short, true)
|
||||
}
|
||||
None => (
|
||||
hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())),
|
||||
hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name)),
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
// FIXME: ModPath::to_smol_str()?
|
||||
let mut item =
|
||||
CompletionItem::new(SymbolKind::Variant, ctx.source_range(), qualified_name.to_string());
|
||||
item.set_documentation(variant.docs(db))
|
||||
.set_deprecated(ctx.is_deprecated(variant))
|
||||
.detail(detail(db, variant, variant_kind));
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
}
|
||||
|
||||
// FIXME: ModPath::to_smol_str()?
|
||||
let short_qualified_name = short_qualified_name.to_string();
|
||||
if variant_kind == hir::StructKind::Tuple {
|
||||
cov_mark::hit!(inserts_parens_for_tuple_enums);
|
||||
let params = Params::Anonymous(variant.fields(db).len());
|
||||
item.add_call_parens(ctx.completion, short_qualified_name, params);
|
||||
} else if qualified {
|
||||
item.lookup_by(short_qualified_name);
|
||||
}
|
||||
|
||||
let ty = variant.parent_enum(ctx.completion.db).ty(ctx.completion.db);
|
||||
item.set_relevance(CompletionRelevance {
|
||||
type_match: compute_type_match(ctx.completion, &ty),
|
||||
..CompletionRelevance::default()
|
||||
});
|
||||
|
||||
if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) {
|
||||
item.ref_match(ref_match);
|
||||
}
|
||||
|
||||
item.build()
|
||||
}
|
||||
|
||||
impl<'a> EnumRender<'a> {
|
||||
fn new(
|
||||
ctx: RenderContext<'a>,
|
||||
local_name: Option<hir::Name>,
|
||||
variant: hir::Variant,
|
||||
path: Option<hir::ModPath>,
|
||||
) -> EnumRender<'a> {
|
||||
let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
|
||||
let variant_kind = variant.kind(ctx.db());
|
||||
fn detail(db: &dyn HirDatabase, variant: hir::Variant, variant_kind: StructKind) -> String {
|
||||
let detail_types = variant.fields(db).into_iter().map(|field| (field.name(db), field.ty(db)));
|
||||
|
||||
let (qualified_name, short_qualified_name) = match &path {
|
||||
Some(path) => {
|
||||
let short = hir::ModPath::from_segments(
|
||||
hir::PathKind::Plain,
|
||||
path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(),
|
||||
);
|
||||
(path.clone(), short)
|
||||
}
|
||||
None => (
|
||||
hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())),
|
||||
hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name)),
|
||||
),
|
||||
};
|
||||
|
||||
EnumRender { ctx, variant, path, qualified_name, short_qualified_name, variant_kind }
|
||||
}
|
||||
fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
|
||||
let mut item = CompletionItem::new(
|
||||
SymbolKind::Variant,
|
||||
self.ctx.source_range(),
|
||||
self.qualified_name.to_string(),
|
||||
);
|
||||
item.set_documentation(self.variant.docs(self.ctx.db()))
|
||||
.set_deprecated(self.ctx.is_deprecated(self.variant))
|
||||
.detail(self.detail());
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
match variant_kind {
|
||||
hir::StructKind::Tuple | hir::StructKind::Unit => {
|
||||
format!("({})", detail_types.format_with(", ", |(_, t), f| f(&t.display(db))))
|
||||
}
|
||||
|
||||
if self.variant_kind == hir::StructKind::Tuple {
|
||||
cov_mark::hit!(inserts_parens_for_tuple_enums);
|
||||
let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len());
|
||||
item.add_call_parens(
|
||||
self.ctx.completion,
|
||||
self.short_qualified_name.to_string(),
|
||||
params,
|
||||
);
|
||||
} else if self.path.is_some() {
|
||||
item.lookup_by(self.short_qualified_name.to_string());
|
||||
hir::StructKind::Record => {
|
||||
format!(
|
||||
"{{{}}}",
|
||||
detail_types.format_with(", ", |(n, t), f| {
|
||||
f(&n)?;
|
||||
f(&": ")?;
|
||||
f(&t.display(db))
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db);
|
||||
item.set_relevance(CompletionRelevance {
|
||||
type_match: compute_type_match(self.ctx.completion, &ty),
|
||||
..CompletionRelevance::default()
|
||||
});
|
||||
|
||||
if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) {
|
||||
item.ref_match(ref_match);
|
||||
}
|
||||
|
||||
item.build()
|
||||
}
|
||||
|
||||
fn detail(&self) -> String {
|
||||
let detail_types = self
|
||||
.variant
|
||||
.fields(self.ctx.db())
|
||||
.into_iter()
|
||||
.map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db())));
|
||||
|
||||
let mut b = String::new();
|
||||
let mut first_run = true;
|
||||
match self.variant_kind {
|
||||
hir::StructKind::Tuple | hir::StructKind::Unit => {
|
||||
format_to!(b, "(");
|
||||
for (_, t) in detail_types {
|
||||
if !mem::take(&mut first_run) {
|
||||
format_to!(b, ", ");
|
||||
}
|
||||
format_to!(b, "{}", t.display(self.ctx.db()));
|
||||
}
|
||||
format_to!(b, ")");
|
||||
}
|
||||
hir::StructKind::Record => {
|
||||
format_to!(b, "{{");
|
||||
for (n, t) in detail_types {
|
||||
if !mem::take(&mut first_run) {
|
||||
format_to!(b, ", ");
|
||||
}
|
||||
format_to!(b, "{}: {}", n, t.display(self.ctx.db()));
|
||||
}
|
||||
format_to!(b, "}}");
|
||||
}
|
||||
}
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
//! Renderer for function calls.
|
||||
|
||||
use hir::{AsAssocItem, HirDisplay};
|
||||
use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
|
||||
use ide_db::SymbolKind;
|
||||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{
|
||||
context::CompletionContext,
|
||||
item::{CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit},
|
||||
render::{
|
||||
builder_ext::Params, compute_exact_name_match, compute_ref_match, compute_type_match,
|
||||
|
@ -13,14 +14,19 @@
|
|||
},
|
||||
};
|
||||
|
||||
enum FuncType {
|
||||
Function,
|
||||
Method(Option<hir::Name>),
|
||||
}
|
||||
|
||||
pub(crate) fn render_fn(
|
||||
ctx: RenderContext<'_>,
|
||||
import_to_add: Option<ImportEdit>,
|
||||
local_name: Option<hir::Name>,
|
||||
fn_: hir::Function,
|
||||
) -> Option<CompletionItem> {
|
||||
func: hir::Function,
|
||||
) -> CompletionItem {
|
||||
let _p = profile::span("render_fn");
|
||||
Some(FunctionRender::new(ctx, None, local_name, fn_, false)?.render(import_to_add))
|
||||
render(ctx, local_name, func, FuncType::Function, import_to_add)
|
||||
}
|
||||
|
||||
pub(crate) fn render_method(
|
||||
|
@ -28,135 +34,120 @@ pub(crate) fn render_method(
|
|||
import_to_add: Option<ImportEdit>,
|
||||
receiver: Option<hir::Name>,
|
||||
local_name: Option<hir::Name>,
|
||||
fn_: hir::Function,
|
||||
) -> Option<CompletionItem> {
|
||||
let _p = profile::span("render_method");
|
||||
Some(FunctionRender::new(ctx, receiver, local_name, fn_, true)?.render(import_to_add))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionRender<'a> {
|
||||
ctx: RenderContext<'a>,
|
||||
name: hir::Name,
|
||||
receiver: Option<hir::Name>,
|
||||
func: hir::Function,
|
||||
is_method: bool,
|
||||
) -> CompletionItem {
|
||||
let _p = profile::span("render_method");
|
||||
render(ctx, local_name, func, FuncType::Method(receiver), import_to_add)
|
||||
}
|
||||
|
||||
impl<'a> FunctionRender<'a> {
|
||||
fn new(
|
||||
ctx: RenderContext<'a>,
|
||||
receiver: Option<hir::Name>,
|
||||
local_name: Option<hir::Name>,
|
||||
fn_: hir::Function,
|
||||
is_method: bool,
|
||||
) -> Option<FunctionRender<'a>> {
|
||||
let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()));
|
||||
fn render(
|
||||
ctx @ RenderContext { completion }: RenderContext<'_>,
|
||||
local_name: Option<hir::Name>,
|
||||
func: hir::Function,
|
||||
func_type: FuncType,
|
||||
import_to_add: Option<ImportEdit>,
|
||||
) -> CompletionItem {
|
||||
let db = completion.db;
|
||||
|
||||
Some(FunctionRender { ctx, name, receiver, func: fn_, is_method })
|
||||
}
|
||||
let name = local_name.unwrap_or_else(|| func.name(db));
|
||||
let params = params(completion, func, &func_type);
|
||||
|
||||
fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
|
||||
let params = self.params();
|
||||
let call = match &self.receiver {
|
||||
Some(receiver) => format!("{}.{}", receiver, &self.name),
|
||||
None => self.name.to_string(),
|
||||
};
|
||||
let mut item = CompletionItem::new(self.kind(), self.ctx.source_range(), call.clone());
|
||||
item.set_documentation(self.ctx.docs(self.func))
|
||||
.set_deprecated(
|
||||
self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
|
||||
)
|
||||
.detail(self.detail())
|
||||
.add_call_parens(self.ctx.completion, call.clone(), params);
|
||||
|
||||
if import_to_add.is_none() {
|
||||
let db = self.ctx.db();
|
||||
if let Some(actm) = self.func.as_assoc_item(db) {
|
||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||
item.trait_name(trt.name(db).to_smol_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
}
|
||||
item.lookup_by(self.name.to_smol_str());
|
||||
|
||||
let ret_type = self.func.ret_type(self.ctx.db());
|
||||
item.set_relevance(CompletionRelevance {
|
||||
type_match: compute_type_match(self.ctx.completion, &ret_type),
|
||||
exact_name_match: compute_exact_name_match(self.ctx.completion, &call),
|
||||
..CompletionRelevance::default()
|
||||
});
|
||||
|
||||
if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ret_type) {
|
||||
// FIXME
|
||||
// For now we don't properly calculate the edits for ref match
|
||||
// completions on methods, so we've disabled them. See #8058.
|
||||
if !self.is_method {
|
||||
item.ref_match(ref_match);
|
||||
}
|
||||
}
|
||||
|
||||
item.build()
|
||||
}
|
||||
|
||||
fn detail(&self) -> String {
|
||||
let ret_ty = self.func.ret_type(self.ctx.db());
|
||||
let mut detail = format!("fn({})", self.params_display());
|
||||
if !ret_ty.is_unit() {
|
||||
format_to!(detail, " -> {}", ret_ty.display(self.ctx.db()));
|
||||
}
|
||||
detail
|
||||
}
|
||||
|
||||
fn params_display(&self) -> String {
|
||||
if let Some(self_param) = self.func.self_param(self.ctx.db()) {
|
||||
let params = self
|
||||
.func
|
||||
.assoc_fn_params(self.ctx.db())
|
||||
.into_iter()
|
||||
.skip(1) // skip the self param because we are manually handling that
|
||||
.map(|p| p.ty().display(self.ctx.db()).to_string());
|
||||
|
||||
std::iter::once(self_param.display(self.ctx.db()).to_owned()).chain(params).join(", ")
|
||||
} else {
|
||||
let params = self
|
||||
.func
|
||||
.assoc_fn_params(self.ctx.db())
|
||||
.into_iter()
|
||||
.map(|p| p.ty().display(self.ctx.db()).to_string())
|
||||
.join(", ");
|
||||
params
|
||||
}
|
||||
}
|
||||
|
||||
fn params(&self) -> Params {
|
||||
let (params, self_param) =
|
||||
if self.ctx.completion.has_dot_receiver() || self.receiver.is_some() {
|
||||
(self.func.method_params(self.ctx.db()).unwrap_or_default(), None)
|
||||
} else {
|
||||
let self_param = self.func.self_param(self.ctx.db());
|
||||
|
||||
let mut assoc_params = self.func.assoc_fn_params(self.ctx.db());
|
||||
if self_param.is_some() {
|
||||
assoc_params.remove(0);
|
||||
}
|
||||
(assoc_params, self_param)
|
||||
};
|
||||
|
||||
Params::Named(self_param, params)
|
||||
}
|
||||
|
||||
fn kind(&self) -> CompletionItemKind {
|
||||
if self.func.self_param(self.ctx.db()).is_some() {
|
||||
// FIXME: SmolStr?
|
||||
let call = match &func_type {
|
||||
FuncType::Method(Some(receiver)) => format!("{}.{}", receiver, &name),
|
||||
_ => name.to_string(),
|
||||
};
|
||||
let mut item = CompletionItem::new(
|
||||
if func.self_param(db).is_some() {
|
||||
CompletionItemKind::Method
|
||||
} else {
|
||||
SymbolKind::Function.into()
|
||||
CompletionItemKind::SymbolKind(SymbolKind::Function)
|
||||
},
|
||||
ctx.source_range(),
|
||||
call.clone(),
|
||||
);
|
||||
item.set_documentation(ctx.docs(func))
|
||||
.set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
|
||||
.detail(detail(db, func))
|
||||
.add_call_parens(completion, call.clone(), params);
|
||||
|
||||
if import_to_add.is_none() {
|
||||
if let Some(actm) = func.as_assoc_item(db) {
|
||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||
item.trait_name(trt.name(db).to_smol_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
}
|
||||
item.lookup_by(name.to_smol_str());
|
||||
|
||||
let ret_type = func.ret_type(db);
|
||||
item.set_relevance(CompletionRelevance {
|
||||
type_match: compute_type_match(completion, &ret_type),
|
||||
exact_name_match: compute_exact_name_match(completion, &call),
|
||||
..CompletionRelevance::default()
|
||||
});
|
||||
|
||||
if let Some(ref_match) = compute_ref_match(completion, &ret_type) {
|
||||
// FIXME
|
||||
// For now we don't properly calculate the edits for ref match
|
||||
// completions on methods, so we've disabled them. See #8058.
|
||||
if matches!(func_type, FuncType::Function) {
|
||||
item.ref_match(ref_match);
|
||||
}
|
||||
}
|
||||
|
||||
item.build()
|
||||
}
|
||||
|
||||
fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
|
||||
let ret_ty = func.ret_type(db);
|
||||
let mut detail = format!("fn({})", params_display(db, func));
|
||||
if !ret_ty.is_unit() {
|
||||
format_to!(detail, " -> {}", ret_ty.display(db));
|
||||
}
|
||||
detail
|
||||
}
|
||||
|
||||
fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String {
|
||||
if let Some(self_param) = func.self_param(db) {
|
||||
let assoc_fn_params = func.assoc_fn_params(db);
|
||||
let params = assoc_fn_params
|
||||
.iter()
|
||||
.skip(1) // skip the self param because we are manually handling that
|
||||
.map(|p| p.ty().display(db));
|
||||
format!(
|
||||
"{}{}",
|
||||
self_param.display(db),
|
||||
params.format_with("", |display, f| {
|
||||
f(&", ")?;
|
||||
f(&display)
|
||||
})
|
||||
)
|
||||
} else {
|
||||
let assoc_fn_params = func.assoc_fn_params(db);
|
||||
assoc_fn_params.iter().map(|p| p.ty().display(db)).join(", ")
|
||||
}
|
||||
}
|
||||
|
||||
fn params(ctx: &CompletionContext<'_>, func: hir::Function, func_type: &FuncType) -> Params {
|
||||
let (params, self_param) =
|
||||
if ctx.has_dot_receiver() || matches!(func_type, FuncType::Method(Some(_))) {
|
||||
(func.method_params(ctx.db).unwrap_or_default(), None)
|
||||
} else {
|
||||
let self_param = func.self_param(ctx.db);
|
||||
|
||||
let mut assoc_params = func.assoc_fn_params(ctx.db);
|
||||
if self_param.is_some() {
|
||||
assoc_params.remove(0);
|
||||
}
|
||||
(assoc_params, self_param)
|
||||
};
|
||||
|
||||
Params::Named(self_param, params)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Renderer for macro invocations.
|
||||
|
||||
use either::Either;
|
||||
use hir::HasSource;
|
||||
use hir::{db::HirDatabase, Documentation, HasSource};
|
||||
use ide_db::SymbolKind;
|
||||
use syntax::{
|
||||
display::{fn_as_proc_macro_label, macro_label},
|
||||
|
@ -21,94 +21,96 @@ pub(crate) fn render_macro(
|
|||
macro_: hir::MacroDef,
|
||||
) -> Option<CompletionItem> {
|
||||
let _p = profile::span("render_macro");
|
||||
MacroRender::new(ctx, name, macro_).render(import_to_add)
|
||||
render(ctx, name, macro_, import_to_add)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MacroRender<'a> {
|
||||
ctx: RenderContext<'a>,
|
||||
name: SmolStr,
|
||||
fn render(
|
||||
ctx @ RenderContext { completion }: RenderContext<'_>,
|
||||
name: hir::Name,
|
||||
macro_: hir::MacroDef,
|
||||
docs: Option<hir::Documentation>,
|
||||
bra: &'static str,
|
||||
ket: &'static str,
|
||||
import_to_add: Option<ImportEdit>,
|
||||
) -> Option<CompletionItem> {
|
||||
let db = completion.db;
|
||||
|
||||
let source_range = if completion.is_immediately_after_macro_bang() {
|
||||
cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
|
||||
completion.token.parent().map(|it| it.text_range())
|
||||
} else {
|
||||
Some(ctx.source_range())
|
||||
}?;
|
||||
|
||||
let name = name.to_smol_str();
|
||||
let docs = ctx.docs(macro_);
|
||||
let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
|
||||
let (bra, ket) =
|
||||
if macro_.is_fn_like() { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
||||
|
||||
let needs_bang = macro_.is_fn_like()
|
||||
&& !matches!(completion.path_kind(), Some(PathKind::Mac | PathKind::Use));
|
||||
|
||||
let mut item = CompletionItem::new(
|
||||
SymbolKind::from(macro_.kind()),
|
||||
source_range,
|
||||
label(&ctx, needs_bang, bra, ket, &name),
|
||||
);
|
||||
item.set_deprecated(ctx.is_deprecated(macro_))
|
||||
.set_detail(detail(db, macro_))
|
||||
.set_documentation(docs);
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
}
|
||||
|
||||
let name = &*name;
|
||||
|
||||
match ctx.snippet_cap() {
|
||||
Some(cap) if needs_bang && !completion.path_is_call() => {
|
||||
let snippet = format!("{}!{}$0{}", name, bra, ket);
|
||||
let lookup = banged_name(name);
|
||||
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
||||
}
|
||||
_ if needs_bang => {
|
||||
let banged_name = banged_name(name);
|
||||
item.insert_text(banged_name.clone()).lookup_by(banged_name);
|
||||
}
|
||||
_ => {
|
||||
cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
|
||||
item.insert_text(name);
|
||||
}
|
||||
};
|
||||
|
||||
Some(item.build())
|
||||
}
|
||||
|
||||
impl<'a> MacroRender<'a> {
|
||||
fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> {
|
||||
let name = name.to_smol_str();
|
||||
let docs = ctx.docs(macro_);
|
||||
let docs_str = docs.as_ref().map_or("", |s| s.as_str());
|
||||
let (bra, ket) =
|
||||
if macro_.is_fn_like() { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
||||
|
||||
MacroRender { ctx, name, macro_, docs, bra, ket }
|
||||
}
|
||||
|
||||
fn render(self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
|
||||
let source_range = if self.ctx.completion.is_immediately_after_macro_bang() {
|
||||
cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
|
||||
self.ctx.completion.token.parent().map(|it| it.text_range())
|
||||
fn label(
|
||||
ctx: &RenderContext<'_>,
|
||||
needs_bang: bool,
|
||||
bra: &str,
|
||||
ket: &str,
|
||||
name: &SmolStr,
|
||||
) -> SmolStr {
|
||||
if needs_bang {
|
||||
if ctx.snippet_cap().is_some() {
|
||||
SmolStr::from_iter([&*name, "!", bra, "…", ket])
|
||||
} else {
|
||||
Some(self.ctx.source_range())
|
||||
}?;
|
||||
let mut item =
|
||||
CompletionItem::new(SymbolKind::from(self.macro_.kind()), source_range, self.label());
|
||||
item.set_deprecated(self.ctx.is_deprecated(self.macro_)).set_detail(self.detail());
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
banged_name(name)
|
||||
}
|
||||
|
||||
let needs_bang = self.macro_.is_fn_like()
|
||||
&& !matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use));
|
||||
let has_parens = self.ctx.completion.path_is_call();
|
||||
|
||||
match self.ctx.snippet_cap() {
|
||||
Some(cap) if needs_bang && !has_parens => {
|
||||
let snippet = format!("{}!{}$0{}", self.name, self.bra, self.ket);
|
||||
let lookup = self.banged_name();
|
||||
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
||||
}
|
||||
_ if needs_bang => {
|
||||
let lookup = self.banged_name();
|
||||
item.insert_text(self.banged_name()).lookup_by(lookup);
|
||||
}
|
||||
_ => {
|
||||
cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
|
||||
item.insert_text(&*self.name);
|
||||
}
|
||||
};
|
||||
|
||||
item.set_documentation(self.docs);
|
||||
Some(item.build())
|
||||
} else {
|
||||
name.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn needs_bang(&self) -> bool {
|
||||
!matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use))
|
||||
}
|
||||
fn banged_name(name: &str) -> SmolStr {
|
||||
SmolStr::from_iter([name, "!"])
|
||||
}
|
||||
|
||||
fn label(&self) -> SmolStr {
|
||||
if !self.macro_.is_fn_like() {
|
||||
self.name.clone()
|
||||
} else if self.needs_bang() && self.ctx.snippet_cap().is_some() {
|
||||
SmolStr::from_iter([&*self.name, "!", self.bra, "…", self.ket])
|
||||
} else {
|
||||
self.banged_name()
|
||||
}
|
||||
}
|
||||
|
||||
fn banged_name(&self) -> SmolStr {
|
||||
SmolStr::from_iter([&*self.name, "!"])
|
||||
}
|
||||
|
||||
fn detail(&self) -> Option<String> {
|
||||
let detail = match self.macro_.source(self.ctx.db())?.value {
|
||||
Either::Left(node) => macro_label(&node),
|
||||
Either::Right(node) => fn_as_proc_macro_label(&node),
|
||||
};
|
||||
Some(detail)
|
||||
}
|
||||
fn detail(db: &dyn HirDatabase, macro_: hir::MacroDef) -> Option<String> {
|
||||
// FIXME: This is parsing the file!
|
||||
let detail = match macro_.source(db)?.value {
|
||||
Either::Left(node) => macro_label(&node),
|
||||
Either::Right(node) => fn_as_proc_macro_label(&node),
|
||||
};
|
||||
Some(detail)
|
||||
}
|
||||
|
||||
fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
|
||||
|
@ -147,7 +149,7 @@ mod tests {
|
|||
fn dont_insert_macro_call_parens_unncessary() {
|
||||
cov_mark::check!(dont_insert_macro_call_parens_unncessary);
|
||||
check_edit(
|
||||
"frobnicate!",
|
||||
"frobnicate",
|
||||
r#"
|
||||
//- /main.rs crate:main deps:foo
|
||||
use foo::$0;
|
||||
|
@ -161,7 +163,7 @@ macro_rules! frobnicate { () => () }
|
|||
);
|
||||
|
||||
check_edit(
|
||||
"frobnicate!",
|
||||
"frobnicate",
|
||||
r#"
|
||||
macro_rules! frobnicate { () => () }
|
||||
fn main() { frob$0!(); }
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
use hir::{AsAssocItem, HasSource};
|
||||
use ide_db::SymbolKind;
|
||||
use syntax::{
|
||||
ast::{HasName, TypeAlias},
|
||||
display::type_label,
|
||||
};
|
||||
use syntax::{ast::HasName, display::type_label};
|
||||
|
||||
use crate::{item::CompletionItem, render::RenderContext};
|
||||
|
||||
|
@ -14,7 +11,7 @@ pub(crate) fn render_type_alias(
|
|||
type_alias: hir::TypeAlias,
|
||||
) -> Option<CompletionItem> {
|
||||
let _p = profile::span("render_type_alias");
|
||||
TypeAliasRender::new(ctx, type_alias)?.render(false)
|
||||
render(ctx, type_alias, false)
|
||||
}
|
||||
|
||||
pub(crate) fn render_type_alias_with_eq(
|
||||
|
@ -22,53 +19,38 @@ pub(crate) fn render_type_alias_with_eq(
|
|||
type_alias: hir::TypeAlias,
|
||||
) -> Option<CompletionItem> {
|
||||
let _p = profile::span("render_type_alias_with_eq");
|
||||
TypeAliasRender::new(ctx, type_alias)?.render(true)
|
||||
render(ctx, type_alias, true)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TypeAliasRender<'a> {
|
||||
ctx: RenderContext<'a>,
|
||||
fn render(
|
||||
ctx: RenderContext<'_>,
|
||||
type_alias: hir::TypeAlias,
|
||||
ast_node: TypeAlias,
|
||||
}
|
||||
with_eq: bool,
|
||||
) -> Option<CompletionItem> {
|
||||
let db = ctx.db();
|
||||
|
||||
impl<'a> TypeAliasRender<'a> {
|
||||
fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> {
|
||||
let ast_node = type_alias.source(ctx.db())?.value;
|
||||
Some(TypeAliasRender { ctx, type_alias, ast_node })
|
||||
}
|
||||
|
||||
fn render(self, with_eq: bool) -> Option<CompletionItem> {
|
||||
let name = self.ast_node.name().map(|name| {
|
||||
if with_eq {
|
||||
format!("{} = ", name.text())
|
||||
} else {
|
||||
name.text().to_string()
|
||||
}
|
||||
})?;
|
||||
let detail = self.detail();
|
||||
|
||||
let mut item =
|
||||
CompletionItem::new(SymbolKind::TypeAlias, self.ctx.source_range(), name.clone());
|
||||
item.set_documentation(self.ctx.docs(self.type_alias))
|
||||
.set_deprecated(
|
||||
self.ctx.is_deprecated(self.type_alias)
|
||||
|| self.ctx.is_deprecated_assoc_item(self.type_alias),
|
||||
)
|
||||
.detail(detail);
|
||||
|
||||
let db = self.ctx.db();
|
||||
if let Some(actm) = self.type_alias.as_assoc_item(db) {
|
||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||
item.trait_name(trt.name(db).to_smol_str());
|
||||
item.insert_text(name);
|
||||
}
|
||||
// FIXME: This parses the file!
|
||||
let ast_node = type_alias.source(db)?.value;
|
||||
let name = ast_node.name().map(|name| {
|
||||
if with_eq {
|
||||
format!("{} = ", name.text())
|
||||
} else {
|
||||
name.text().to_string()
|
||||
}
|
||||
})?;
|
||||
let detail = type_label(&ast_node);
|
||||
|
||||
Some(item.build())
|
||||
let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name.clone());
|
||||
item.set_documentation(ctx.docs(type_alias))
|
||||
.set_deprecated(ctx.is_deprecated(type_alias) || ctx.is_deprecated_assoc_item(type_alias))
|
||||
.detail(detail);
|
||||
|
||||
if let Some(actm) = type_alias.as_assoc_item(db) {
|
||||
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
||||
item.trait_name(trt.name(db).to_smol_str());
|
||||
item.insert_text(name);
|
||||
}
|
||||
}
|
||||
|
||||
fn detail(&self) -> String {
|
||||
type_label(&self.ast_node)
|
||||
}
|
||||
Some(item.build())
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ macro_rules! foo_ { {} => {} }
|
|||
"#,
|
||||
expect![[r#"
|
||||
st Foo
|
||||
ma foo! macro_rules! foo_
|
||||
ma foo macro_rules! foo_
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue