10699: internal: Make CompletionItem `label` and `lookup` fields `SmolStr`s r=Veykril a=Veykril

This replaces a bunch of String clones with SmolStr clones, though also makes a few parts a bit more expensive(mainly things involving `format!`ted strings as labels).


Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2021-11-07 11:13:15 +00:00 committed by GitHub
commit 2c0f433fd2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 94 additions and 109 deletions

View file

@ -66,24 +66,21 @@ impl CfgOptions {
} }
} }
pub fn get_cfg_keys(&self) -> Vec<&SmolStr> { pub fn get_cfg_keys(&self) -> impl Iterator<Item = &SmolStr> {
self.enabled self.enabled.iter().map(|x| match x {
.iter() CfgAtom::Flag(key) => key,
.map(|x| match x { CfgAtom::KeyValue { key, .. } => key,
CfgAtom::Flag(key) => key, })
CfgAtom::KeyValue { key, .. } => key,
})
.collect()
} }
pub fn get_cfg_values(&self, cfg_key: &str) -> Vec<&SmolStr> { pub fn get_cfg_values<'a>(
self.enabled &'a self,
.iter() cfg_key: &'a str,
.filter_map(|x| match x { ) -> impl Iterator<Item = &'a SmolStr> + 'a {
CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value), self.enabled.iter().filter_map(move |x| match x {
_ => None, CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value),
}) _ => None,
.collect() })
} }
} }

View file

@ -104,7 +104,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
let mut item = CompletionItem::new( let mut item = CompletionItem::new(
CompletionItemKind::Attribute, CompletionItemKind::Attribute,
ctx.source_range(), ctx.source_range(),
name.to_string(), name.to_smol_str(),
); );
if let Some(docs) = mac.docs(ctx.sema.db) { if let Some(docs) = mac.docs(ctx.sema.db) {
item.documentation(docs); item.documentation(docs);

View file

@ -31,13 +31,11 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion), Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
Some(name) => { Some(name) => {
if let Some(krate) = ctx.krate { if let Some(krate) = ctx.krate {
krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| { krate.potential_cfg(ctx.db).get_cfg_values(&name).cloned().for_each(|s| {
let mut item = CompletionItem::new( let insert_text = format!(r#""{}""#, s);
CompletionItemKind::Attribute, let mut item =
ctx.source_range(), CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), s);
s.as_str(), item.insert_text(insert_text);
);
item.insert_text(format!(r#""{}""#, s));
acc.add(item.build()); acc.add(item.build());
}) })
@ -45,12 +43,9 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
} }
None => { None => {
if let Some(krate) = ctx.krate { if let Some(krate) = ctx.krate {
krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| { krate.potential_cfg(ctx.db).get_cfg_keys().cloned().for_each(|s| {
let item = CompletionItem::new( let item =
CompletionItemKind::Attribute, CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), s);
ctx.source_range(),
s.as_str(),
);
acc.add(item.build()); acc.add(item.build());
}) })
} }

View file

@ -3,7 +3,7 @@ use hir::{HasAttrs, MacroDef, MacroKind};
use ide_db::helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs}; use ide_db::helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs};
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use syntax::{ast, SyntaxKind}; use syntax::{ast, SmolStr, SyntaxKind};
use crate::{ use crate::{
completions::flyimport::compute_fuzzy_completion_order_key, completions::flyimport::compute_fuzzy_completion_order_key,
@ -30,7 +30,6 @@ pub(super) fn complete_derive(
} }
let name = name.to_smol_str(); let name = name.to_smol_str();
let label;
let (label, lookup) = match core.zip(mac.module(ctx.db).map(|it| it.krate())) { let (label, lookup) = match core.zip(mac.module(ctx.db).map(|it| it.krate())) {
// show derive dependencies for `core`/`std` derives // show derive dependencies for `core`/`std` derives
Some((core, mac_krate)) if core == mac_krate => { Some((core, mac_krate)) if core == mac_krate => {
@ -48,13 +47,13 @@ pub(super) fn complete_derive(
}, },
)); ));
let lookup = components.join(", "); let lookup = components.join(", ");
label = components.iter().rev().join(", "); let label = Itertools::intersperse(components.into_iter().rev(), ", ");
(label.as_str(), Some(lookup)) (SmolStr::from_iter(label), Some(lookup))
} else { } else {
(&*name, None) (name, None)
} }
} }
_ => (&*name, None), _ => (name, None),
}; };
let mut item = let mut item =
@ -68,7 +67,7 @@ pub(super) fn complete_derive(
item.add_to(acc); item.add_to(acc);
} }
flyimport_attribute(ctx, acc); flyimport_attribute(acc, ctx);
} }
fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> { fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
@ -83,7 +82,7 @@ fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
result result
} }
fn flyimport_attribute(ctx: &CompletionContext, acc: &mut Completions) -> Option<()> { fn flyimport_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
if ctx.token.kind() != SyntaxKind::IDENT { if ctx.token.kind() != SyntaxKind::IDENT {
return None; return None;
}; };
@ -115,7 +114,7 @@ fn flyimport_attribute(ctx: &CompletionContext, acc: &mut Completions) -> Option
let mut item = CompletionItem::new( let mut item = CompletionItem::new(
CompletionItemKind::Attribute, CompletionItemKind::Attribute,
ctx.source_range(), ctx.source_range(),
mac.name(ctx.db)?.to_string(), mac.name(ctx.db)?.to_smol_str(),
); );
item.add_import(ImportEdit { import, scope: import_scope.clone() }); item.add_import(ImportEdit { import, scope: import_scope.clone() });
if let Some(docs) = mac.docs(ctx.db) { if let Some(docs) = mac.docs(ctx.db) {

View file

@ -30,6 +30,7 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
} }
func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
if let Some(pat) = param.pat() { if let Some(pat) = param.pat() {
// FIXME: We should be able to turn these into SmolStr without having to allocate a String
let text = param.syntax().text().to_string(); let text = param.syntax().text().to_string();
let lookup = pat.syntax().text().to_string(); let lookup = pat.syntax().text().to_string();
params.entry(text).or_insert(lookup); params.entry(text).or_insert(lookup);
@ -59,7 +60,7 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
let self_completion_items = ["self", "&self", "mut self", "&mut self"]; let self_completion_items = ["self", "&self", "mut self", "&mut self"];
if ctx.impl_def.is_some() && me?.param_list()?.params().next().is_none() { if ctx.impl_def.is_some() && me?.param_list()?.params().next().is_none() {
self_completion_items.iter().for_each(|self_item| { self_completion_items.into_iter().for_each(|self_item| {
add_new_item_to_acc(ctx, acc, self_item.to_string(), self_item.to_string()) add_new_item_to_acc(ctx, acc, self_item.to_string(), self_item.to_string())
}); });
} }

View file

@ -27,7 +27,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
return; return;
} }
let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); let mut add_keyword = |kw, snippet| add_keyword(acc, ctx, kw, snippet);
let expects_assoc_item = ctx.expects_assoc_item(); let expects_assoc_item = ctx.expects_assoc_item();
let has_block_expr_parent = ctx.has_block_expr_parent(); let has_block_expr_parent = ctx.has_block_expr_parent();
@ -157,7 +157,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
) )
} }
fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) { fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) {
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
match ctx.config.snippet_cap { match ctx.config.snippet_cap {

View file

@ -93,7 +93,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
if ctx.in_use_tree() { if ctx.in_use_tree() {
if let hir::ScopeDef::Unknown = def { if let hir::ScopeDef::Unknown = def {
if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() { if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() {
if name_ref.syntax().text() == name.to_string().as_str() { if name_ref.syntax().text() == name.to_smol_str().as_str() {
// for `use self::foo$0`, don't suggest `foo` as a completion // for `use self::foo$0`, don't suggest `foo` as a completion
cov_mark::hit!(dont_complete_current_use); cov_mark::hit!(dont_complete_current_use);
continue; continue;

View file

@ -133,7 +133,7 @@ fn add_function_impl(
func: hir::Function, func: hir::Function,
impl_def: hir::Impl, impl_def: hir::Impl,
) { ) {
let fn_name = func.name(ctx.db).to_string(); let fn_name = func.name(ctx.db).to_smol_str();
let label = if func.assoc_fn_params(ctx.db).is_empty() { let label = if func.assoc_fn_params(ctx.db).is_empty() {
format!("fn {}()", fn_name) format!("fn {}()", fn_name)
@ -205,12 +205,12 @@ fn add_type_alias_impl(
ctx: &CompletionContext, ctx: &CompletionContext,
type_alias: hir::TypeAlias, type_alias: hir::TypeAlias,
) { ) {
let alias_name = type_alias.name(ctx.db).to_string(); let alias_name = type_alias.name(ctx.db).to_smol_str();
let snippet = format!("type {} = ", alias_name); let snippet = format!("type {} = ", alias_name);
let range = replacement_range(ctx, type_def_node); let range = replacement_range(ctx, type_def_node);
let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), snippet.clone()); let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), &snippet);
item.text_edit(TextEdit::replace(range, snippet)) item.text_edit(TextEdit::replace(range, snippet))
.lookup_by(alias_name) .lookup_by(alias_name)
.set_documentation(type_alias.docs(ctx.db)); .set_documentation(type_alias.docs(ctx.db));
@ -224,7 +224,7 @@ fn add_const_impl(
const_: hir::Const, const_: hir::Const,
impl_def: hir::Impl, impl_def: hir::Impl,
) { ) {
let const_name = const_.name(ctx.db).map(|n| n.to_string()); let const_name = const_.name(ctx.db).map(|n| n.to_smol_str());
if let Some(const_name) = const_name { if let Some(const_name) = const_name {
if let Some(source) = const_.source(ctx.db) { if let Some(source) = const_.source(ctx.db) {
@ -238,8 +238,7 @@ fn add_const_impl(
let snippet = make_const_compl_syntax(&transformed_const); let snippet = make_const_compl_syntax(&transformed_const);
let range = replacement_range(ctx, const_def_node); let range = replacement_range(ctx, const_def_node);
let mut item = let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), &snippet);
CompletionItem::new(SymbolKind::Const, ctx.source_range(), snippet.clone());
item.text_edit(TextEdit::replace(range, snippet)) item.text_edit(TextEdit::replace(range, snippet))
.lookup_by(const_name) .lookup_by(const_name)
.set_documentation(const_.docs(ctx.db)); .set_documentation(const_.docs(ctx.db));

View file

@ -12,8 +12,8 @@ use ide_db::{
SymbolKind, SymbolKind,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use stdx::{format_to, impl_from, never}; use stdx::{impl_from, never};
use syntax::{algo, TextRange}; use syntax::{algo, SmolStr, TextRange};
use text_edit::TextEdit; use text_edit::TextEdit;
/// `CompletionItem` describes a single completion variant in the editor pop-up. /// `CompletionItem` describes a single completion variant in the editor pop-up.
@ -22,7 +22,7 @@ use text_edit::TextEdit;
#[derive(Clone)] #[derive(Clone)]
pub struct CompletionItem { pub struct CompletionItem {
/// Label in the completion pop up which identifies completion. /// Label in the completion pop up which identifies completion.
label: String, label: SmolStr,
/// Range of identifier that is being completed. /// Range of identifier that is being completed.
/// ///
/// It should be used primarily for UI, but we also use this to convert /// It should be used primarily for UI, but we also use this to convert
@ -46,7 +46,7 @@ pub struct CompletionItem {
/// ///
/// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
/// contains `bar` sub sequence), and `quux` will rejected. /// contains `bar` sub sequence), and `quux` will rejected.
lookup: Option<String>, lookup: Option<SmolStr>,
/// Additional info to show in the UI pop up. /// Additional info to show in the UI pop up.
detail: Option<String>, detail: Option<String>,
@ -268,7 +268,7 @@ impl CompletionItem {
pub(crate) fn new( pub(crate) fn new(
kind: impl Into<CompletionItemKind>, kind: impl Into<CompletionItemKind>,
source_range: TextRange, source_range: TextRange,
label: impl Into<String>, label: impl Into<SmolStr>,
) -> Builder { ) -> Builder {
let label = label.into(); let label = label.into();
Builder { Builder {
@ -379,13 +379,13 @@ impl ImportEdit {
pub(crate) struct Builder { pub(crate) struct Builder {
source_range: TextRange, source_range: TextRange,
imports_to_add: SmallVec<[ImportEdit; 1]>, imports_to_add: SmallVec<[ImportEdit; 1]>,
trait_name: Option<String>, trait_name: Option<SmolStr>,
label: String, label: SmolStr,
insert_text: Option<String>, insert_text: Option<String>,
is_snippet: bool, is_snippet: bool,
detail: Option<String>, detail: Option<String>,
documentation: Option<Documentation>, documentation: Option<Documentation>,
lookup: Option<String>, lookup: Option<SmolStr>,
kind: CompletionItemKind, kind: CompletionItemKind,
text_edit: Option<TextEdit>, text_edit: Option<TextEdit>,
deprecated: bool, deprecated: bool,
@ -400,25 +400,21 @@ impl Builder {
let mut label = self.label; let mut label = self.label;
let mut lookup = self.lookup; let mut lookup = self.lookup;
let mut insert_text = self.insert_text; let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
if let [import_edit] = &*self.imports_to_add { if let [import_edit] = &*self.imports_to_add {
// snippets can have multiple imports, but normal completions only have up to one // snippets can have multiple imports, but normal completions only have up to one
if let Some(original_path) = import_edit.import.original_path.as_ref() { if let Some(original_path) = import_edit.import.original_path.as_ref() {
lookup = lookup.or_else(|| Some(label.clone())); lookup = lookup.or_else(|| Some(label.clone()));
insert_text = insert_text.or_else(|| Some(label.clone())); label = SmolStr::from(format!("{} (use {})", label, original_path));
format_to!(label, " (use {})", original_path)
} }
} else if let Some(trait_name) = self.trait_name { } else if let Some(trait_name) = self.trait_name {
insert_text = insert_text.or_else(|| Some(label.clone())); label = SmolStr::from(format!("{} (as {})", label, trait_name));
format_to!(label, " (as {})", trait_name)
} }
let text_edit = match self.text_edit { let text_edit = match self.text_edit {
Some(it) => it, Some(it) => it,
None => { None => TextEdit::replace(self.source_range, insert_text),
TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
}
}; };
CompletionItem { CompletionItem {
@ -437,16 +433,16 @@ impl Builder {
import_to_add: self.imports_to_add, import_to_add: self.imports_to_add,
} }
} }
pub(crate) fn lookup_by(&mut self, lookup: impl Into<String>) -> &mut Builder { pub(crate) fn lookup_by(&mut self, lookup: impl Into<SmolStr>) -> &mut Builder {
self.lookup = Some(lookup.into()); self.lookup = Some(lookup.into());
self self
} }
pub(crate) fn label(&mut self, label: impl Into<String>) -> &mut Builder { pub(crate) fn label(&mut self, label: impl Into<SmolStr>) -> &mut Builder {
self.label = label.into(); self.label = label.into();
self self
} }
pub(crate) fn trait_name(&mut self, trait_name: impl Into<String>) -> &mut Builder { pub(crate) fn trait_name(&mut self, trait_name: SmolStr) -> &mut Builder {
self.trait_name = Some(trait_name.into()); self.trait_name = Some(trait_name);
self self
} }
pub(crate) fn insert_text(&mut self, insert_text: impl Into<String>) -> &mut Builder { pub(crate) fn insert_text(&mut self, insert_text: impl Into<String>) -> &mut Builder {

View file

@ -83,11 +83,11 @@ pub(crate) fn render_field(
ty: &hir::Type, ty: &hir::Type,
) -> CompletionItem { ) -> CompletionItem {
let is_deprecated = ctx.is_deprecated(field); let is_deprecated = ctx.is_deprecated(field);
let name = field.name(ctx.db()).to_string(); let name = field.name(ctx.db()).to_smol_str();
let mut item = CompletionItem::new( let mut item = CompletionItem::new(
SymbolKind::Field, SymbolKind::Field,
ctx.source_range(), ctx.source_range(),
receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name).into()),
); );
item.set_relevance(CompletionRelevance { item.set_relevance(CompletionRelevance {
type_match: compute_type_match(ctx.completion, ty), type_match: compute_type_match(ctx.completion, ty),
@ -97,7 +97,7 @@ pub(crate) fn render_field(
item.detail(ty.display(ctx.db()).to_string()) item.detail(ty.display(ctx.db()).to_string())
.set_documentation(field.docs(ctx.db())) .set_documentation(field.docs(ctx.db()))
.set_deprecated(is_deprecated) .set_deprecated(is_deprecated)
.lookup_by(name.as_str()); .lookup_by(name.clone());
let is_keyword = SyntaxKind::from_keyword(name.as_str()).is_some(); let is_keyword = SyntaxKind::from_keyword(name.as_str()).is_some();
if is_keyword && !matches!(name.as_str(), "self" | "crate" | "super" | "Self") { if is_keyword && !matches!(name.as_str(), "self" | "crate" | "super" | "Self") {
item.insert_text(format!("r#{}", name)); item.insert_text(format!("r#{}", name));
@ -199,7 +199,7 @@ fn render_resolution_(
let mut item = CompletionItem::new( let mut item = CompletionItem::new(
CompletionItemKind::UnresolvedReference, CompletionItemKind::UnresolvedReference,
ctx.source_range(), ctx.source_range(),
local_name.to_string(), local_name.to_smol_str(),
); );
if let Some(import_to_add) = import_to_add { if let Some(import_to_add) = import_to_add {
item.add_import(import_to_add); item.add_import(import_to_add);
@ -208,7 +208,7 @@ fn render_resolution_(
} }
}; };
let local_name = local_name.to_string(); let local_name = local_name.to_smol_str();
let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone()); let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone());
if let hir::ScopeDef::Local(local) = resolution { if let hir::ScopeDef::Local(local) = resolution {
let ty = local.ty(ctx.db()); let ty = local.ty(ctx.db());

View file

@ -2,10 +2,7 @@
use hir::{AsAssocItem, HasSource}; use hir::{AsAssocItem, HasSource};
use ide_db::SymbolKind; use ide_db::SymbolKind;
use syntax::{ use syntax::{ast::Const, display::const_label};
ast::{Const, HasName},
display::const_label,
};
use crate::{item::CompletionItem, render::RenderContext}; use crate::{item::CompletionItem, render::RenderContext};
@ -27,7 +24,7 @@ impl<'a> ConstRender<'a> {
} }
fn render(self) -> Option<CompletionItem> { fn render(self) -> Option<CompletionItem> {
let name = self.name()?; let name = self.const_.name(self.ctx.db())?.to_smol_str();
let detail = self.detail(); let detail = self.detail();
let mut item = let mut item =
@ -42,7 +39,7 @@ impl<'a> ConstRender<'a> {
let db = self.ctx.db(); let db = self.ctx.db();
if let Some(actm) = self.const_.as_assoc_item(db) { if let Some(actm) = self.const_.as_assoc_item(db) {
if let Some(trt) = actm.containing_trait_or_trait_impl(db) { if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
item.trait_name(trt.name(db).to_string()); item.trait_name(trt.name(db).to_smol_str());
item.insert_text(name); item.insert_text(name);
} }
} }
@ -50,10 +47,6 @@ impl<'a> ConstRender<'a> {
Some(item.build()) Some(item.build())
} }
fn name(&self) -> Option<String> {
self.ast_node.name().map(|name| name.text().to_string())
}
fn detail(&self) -> String { fn detail(&self) -> String {
const_label(&self.ast_node) const_label(&self.ast_node)
} }

View file

@ -38,7 +38,7 @@ pub(crate) fn render_method(
#[derive(Debug)] #[derive(Debug)]
struct FunctionRender<'a> { struct FunctionRender<'a> {
ctx: RenderContext<'a>, ctx: RenderContext<'a>,
name: String, name: hir::Name,
receiver: Option<hir::Name>, receiver: Option<hir::Name>,
func: hir::Function, func: hir::Function,
/// NB: having `ast::Fn` here might or might not be a good idea. The problem /// NB: having `ast::Fn` here might or might not be a good idea. The problem
@ -67,7 +67,7 @@ impl<'a> FunctionRender<'a> {
fn_: hir::Function, fn_: hir::Function,
is_method: bool, is_method: bool,
) -> Option<FunctionRender<'a>> { ) -> Option<FunctionRender<'a>> {
let name = local_name.unwrap_or_else(|| fn_.name(ctx.db())).to_string(); let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()));
let ast_node = fn_.source(ctx.db())?.value; let ast_node = fn_.source(ctx.db())?.value;
Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method }) Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method })
@ -77,7 +77,7 @@ impl<'a> FunctionRender<'a> {
let params = self.params(); let params = self.params();
let call = match &self.receiver { let call = match &self.receiver {
Some(receiver) => format!("{}.{}", receiver, &self.name), Some(receiver) => format!("{}.{}", receiver, &self.name),
None => self.name.clone(), None => self.name.to_string(),
}; };
let mut item = CompletionItem::new(self.kind(), self.ctx.source_range(), call.clone()); let mut item = CompletionItem::new(self.kind(), self.ctx.source_range(), call.clone());
item.set_documentation(self.ctx.docs(self.func)) item.set_documentation(self.ctx.docs(self.func))
@ -91,7 +91,7 @@ impl<'a> FunctionRender<'a> {
let db = self.ctx.db(); let db = self.ctx.db();
if let Some(actm) = self.func.as_assoc_item(db) { if let Some(actm) = self.func.as_assoc_item(db) {
if let Some(trt) = actm.containing_trait_or_trait_impl(db) { if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
item.trait_name(trt.name(db).to_string()); item.trait_name(trt.name(db).to_smol_str());
} }
} }
} }
@ -99,7 +99,7 @@ impl<'a> FunctionRender<'a> {
if let Some(import_to_add) = import_to_add { if let Some(import_to_add) = import_to_add {
item.add_import(import_to_add); item.add_import(import_to_add);
} }
item.lookup_by(self.name); item.lookup_by(self.name.to_smol_str());
let ret_type = self.func.ret_type(self.ctx.db()); let ret_type = self.func.ret_type(self.ctx.db());
item.set_relevance(CompletionRelevance { item.set_relevance(CompletionRelevance {

View file

@ -2,7 +2,7 @@
use hir::HasSource; use hir::HasSource;
use ide_db::SymbolKind; use ide_db::SymbolKind;
use syntax::display::macro_label; use syntax::{display::macro_label, SmolStr};
use crate::{ use crate::{
context::CallKind, context::CallKind,
@ -23,7 +23,7 @@ pub(crate) fn render_macro(
#[derive(Debug)] #[derive(Debug)]
struct MacroRender<'a> { struct MacroRender<'a> {
ctx: RenderContext<'a>, ctx: RenderContext<'a>,
name: String, name: SmolStr,
macro_: hir::MacroDef, macro_: hir::MacroDef,
docs: Option<hir::Documentation>, docs: Option<hir::Documentation>,
bra: &'static str, bra: &'static str,
@ -32,7 +32,7 @@ struct MacroRender<'a> {
impl<'a> MacroRender<'a> { impl<'a> MacroRender<'a> {
fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> { fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> {
let name = name.to_string(); let name = name.to_smol_str();
let docs = ctx.docs(macro_); let docs = ctx.docs(macro_);
let docs_str = docs.as_ref().map_or("", |s| s.as_str()); let docs_str = docs.as_ref().map_or("", |s| s.as_str());
let (bra, ket) = guess_macro_braces(&name, docs_str); let (bra, ket) = guess_macro_braces(&name, docs_str);
@ -47,7 +47,7 @@ impl<'a> MacroRender<'a> {
} else { } else {
Some(self.ctx.source_range()) Some(self.ctx.source_range())
}?; }?;
let mut item = CompletionItem::new(SymbolKind::Macro, source_range, &self.label()); let mut item = CompletionItem::new(SymbolKind::Macro, source_range, self.label());
item.set_documentation(self.docs.clone()) item.set_documentation(self.docs.clone())
.set_deprecated(self.ctx.is_deprecated(self.macro_)) .set_deprecated(self.ctx.is_deprecated(self.macro_))
.set_detail(self.detail()); .set_detail(self.detail());
@ -72,7 +72,7 @@ impl<'a> MacroRender<'a> {
} }
_ => { _ => {
cov_mark::hit!(dont_insert_macro_call_parens_unncessary); cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
item.insert_text(&self.name); item.insert_text(&*self.name);
} }
}; };
@ -84,18 +84,18 @@ impl<'a> MacroRender<'a> {
&& !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
} }
fn label(&self) -> String { fn label(&self) -> SmolStr {
if self.needs_bang() && self.ctx.snippet_cap().is_some() { if self.needs_bang() && self.ctx.snippet_cap().is_some() {
format!("{}!{}{}", self.name, self.bra, self.ket) SmolStr::from_iter([&*self.name, "!", self.bra, "", self.ket])
} else if self.macro_.kind() == hir::MacroKind::Derive { } else if self.macro_.kind() == hir::MacroKind::Derive {
self.name.to_string() self.name.clone()
} else { } else {
self.banged_name() self.banged_name()
} }
} }
fn banged_name(&self) -> String { fn banged_name(&self) -> SmolStr {
format!("{}!", self.name) SmolStr::from_iter([&*self.name, "!"])
} }
fn detail(&self) -> Option<String> { fn detail(&self) -> Option<String> {

View file

@ -3,6 +3,7 @@
use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
use ide_db::helpers::SnippetCap; use ide_db::helpers::SnippetCap;
use itertools::Itertools; use itertools::Itertools;
use syntax::SmolStr;
use crate::{ use crate::{
context::{ParamKind, PatternContext}, context::{ParamKind, PatternContext},
@ -25,7 +26,7 @@ pub(crate) fn render_struct_pat(
return None; return None;
} }
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?; let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?;
Some(build_completion(ctx, name, pat, strukt)) Some(build_completion(ctx, name, pat, strukt))
@ -43,8 +44,8 @@ pub(crate) fn render_variant_pat(
let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?; let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?;
let name = match &path { let name = match &path {
Some(path) => path.to_string(), Some(path) => path.to_string().into(),
None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(), None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_smol_str(),
}; };
let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?; let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?;
@ -53,7 +54,7 @@ pub(crate) fn render_variant_pat(
fn build_completion( fn build_completion(
ctx: RenderContext<'_>, ctx: RenderContext<'_>,
name: String, name: SmolStr,
pat: String, pat: String,
def: impl HasAttrs + Copy, def: impl HasAttrs + Copy,
) -> CompletionItem { ) -> CompletionItem {

View file

@ -3,6 +3,7 @@
use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
use ide_db::helpers::SnippetCap; use ide_db::helpers::SnippetCap;
use itertools::Itertools; use itertools::Itertools;
use syntax::SmolStr;
use crate::{render::RenderContext, CompletionItem, CompletionItemKind}; use crate::{render::RenderContext, CompletionItem, CompletionItemKind};
@ -21,7 +22,7 @@ pub(crate) fn render_struct_literal(
return None; return None;
} }
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
let literal = render_literal(&ctx, &name, strukt.kind(ctx.db()), &visible_fields)?; let literal = render_literal(&ctx, &name, strukt.kind(ctx.db()), &visible_fields)?;
Some(build_completion(ctx, name, literal, strukt)) Some(build_completion(ctx, name, literal, strukt))
@ -29,12 +30,15 @@ pub(crate) fn render_struct_literal(
fn build_completion( fn build_completion(
ctx: RenderContext<'_>, ctx: RenderContext<'_>,
name: String, name: SmolStr,
literal: String, literal: String,
def: impl HasAttrs + Copy, def: impl HasAttrs + Copy,
) -> CompletionItem { ) -> CompletionItem {
let mut item = let mut item = CompletionItem::new(
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), name + " {…}"); CompletionItemKind::Snippet,
ctx.source_range(),
SmolStr::from_iter([&name, " {…}"]),
);
item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&literal); item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&literal);
match ctx.snippet_cap() { match ctx.snippet_cap() {
Some(snippet_cap) => item.insert_snippet(snippet_cap, literal), Some(snippet_cap) => item.insert_snippet(snippet_cap, literal),

View file

@ -58,7 +58,7 @@ impl<'a> TypeAliasRender<'a> {
let db = self.ctx.db(); let db = self.ctx.db();
if let Some(actm) = self.type_alias.as_assoc_item(db) { if let Some(actm) = self.type_alias.as_assoc_item(db) {
if let Some(trt) = actm.containing_trait_or_trait_impl(db) { if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
item.trait_name(trt.name(db).to_string()); item.trait_name(trt.name(db).to_smol_str());
item.insert_text(name); item.insert_text(name);
} }
} }

View file

@ -18,7 +18,7 @@ rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" }
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
once_cell = "1.3.1" once_cell = "1.3.1"
indexmap = "1.4.0" indexmap = "1.4.0"
smol_str = "0.1.15" smol_str = "0.1.21"
stdx = { path = "../stdx", version = "0.0.0" } stdx = { path = "../stdx", version = "0.0.0" }
text_edit = { path = "../text_edit", version = "0.0.0" } text_edit = { path = "../text_edit", version = "0.0.0" }