Skip to content

Commit c16d04e

Browse files
bors[bot]Veykril
andauthored
Merge #10561
10561: internal: Don't turn local names into strings in CompletionContext r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents dd8e831 + 791a2af commit c16d04e

File tree

4 files changed

+97
-61
lines changed

4 files changed

+97
-61
lines changed

crates/hir_expand/src/name.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,30 @@ impl Name {
6767
Name::new_text("[missing name]".into())
6868
}
6969

70+
/// Returns the tuple index this name represents if it is a tuple field.
7071
pub fn as_tuple_index(&self) -> Option<usize> {
7172
match self.0 {
7273
Repr::TupleField(idx) => Some(idx),
7374
_ => None,
7475
}
7576
}
77+
78+
/// Returns the text this name represents if it isn't a tuple field.
79+
pub fn as_text(&self) -> Option<SmolStr> {
80+
match &self.0 {
81+
Repr::Text(it) => Some(it.clone()),
82+
_ => None,
83+
}
84+
}
85+
86+
/// Returns the textual representation of this name as a [`SmolStr`].
87+
/// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper.
88+
pub fn to_smol_str(&self) -> SmolStr {
89+
match &self.0 {
90+
Repr::Text(it) => it.clone(),
91+
Repr::TupleField(it) => SmolStr::new(&it.to_string()),
92+
}
93+
}
7694
}
7795

7896
pub trait AsName {

crates/ide_completion/src/context.rs

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ pub(crate) struct CompletionContext<'a> {
102102
pub(super) function_def: Option<ast::Fn>,
103103
/// The parent impl of the cursor position if it exists.
104104
pub(super) impl_def: Option<ast::Impl>,
105+
/// The NameLike under the cursor in the original file if it exists.
105106
pub(super) name_syntax: Option<ast::NameLike>,
107+
pub(super) incomplete_let: bool,
106108

107109
pub(super) completion_location: Option<ImmediateLocation>,
108110
pub(super) prev_sibling: Option<ImmediatePrevSibling>,
@@ -112,9 +114,7 @@ pub(crate) struct CompletionContext<'a> {
112114
pub(super) lifetime_ctx: Option<LifetimeContext>,
113115
pub(super) pattern_ctx: Option<PatternContext>,
114116
pub(super) path_context: Option<PathCompletionContext>,
115-
pub(super) locals: Vec<(String, Local)>,
116-
117-
pub(super) incomplete_let: bool,
117+
pub(super) locals: Vec<(Name, Local)>,
118118

119119
no_completion_required: bool,
120120
}
@@ -148,7 +148,7 @@ impl<'a> CompletionContext<'a> {
148148
let mut locals = vec![];
149149
scope.process_all_names(&mut |name, scope| {
150150
if let ScopeDef::Local(local) = scope {
151-
locals.push((name.to_string(), local));
151+
locals.push((name, local));
152152
}
153153
});
154154
let mut ctx = CompletionContext {
@@ -492,14 +492,6 @@ impl<'a> CompletionContext<'a> {
492492
false
493493
}
494494

495-
fn fill_impl_def(&mut self) {
496-
self.impl_def = self
497-
.sema
498-
.token_ancestors_with_macros(self.token.clone())
499-
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
500-
.find_map(ast::Impl::cast);
501-
}
502-
503495
fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
504496
let mut node = match self.token.parent() {
505497
Some(it) => it,
@@ -654,6 +646,16 @@ impl<'a> CompletionContext<'a> {
654646
self.prev_sibling = determine_prev_sibling(&name_like);
655647
self.name_syntax =
656648
find_node_at_offset(original_file, name_like.syntax().text_range().start());
649+
self.impl_def = self
650+
.sema
651+
.token_ancestors_with_macros(self.token.clone())
652+
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
653+
.find_map(ast::Impl::cast);
654+
self.function_def = self
655+
.sema
656+
.token_ancestors_with_macros(self.token.clone())
657+
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
658+
.find_map(ast::Fn::cast);
657659
match name_like {
658660
ast::NameLike::Lifetime(lifetime) => {
659661
self.classify_lifetime(original_file, lifetime, offset);
@@ -691,8 +693,6 @@ impl<'a> CompletionContext<'a> {
691693
}
692694

693695
fn classify_name(&mut self, name: ast::Name) {
694-
self.fill_impl_def();
695-
696696
if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
697697
let is_name_in_field_pat = bind_pat
698698
.syntax()
@@ -740,14 +740,6 @@ impl<'a> CompletionContext<'a> {
740740
}
741741

742742
fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) {
743-
self.fill_impl_def();
744-
745-
self.function_def = self
746-
.sema
747-
.token_ancestors_with_macros(self.token.clone())
748-
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
749-
.find_map(ast::Fn::cast);
750-
751743
let parent = match name_ref.syntax().parent() {
752744
Some(it) => it,
753745
None => return,

crates/ide_completion/src/render/builder_ext.rs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! Extensions for `Builder` structure required for item rendering.
22
3+
use either::Either;
34
use itertools::Itertools;
5+
use syntax::ast::{self, HasName};
46

57
use crate::{context::CallKind, item::Builder, patterns::ImmediateLocation, CompletionContext};
68

79
#[derive(Debug)]
810
pub(super) enum Params {
9-
Named(Vec<String>),
11+
Named(Vec<(Either<ast::SelfParam, ast::Param>, hir::Param)>),
1012
Anonymous(usize),
1113
}
1214

@@ -76,10 +78,46 @@ impl Builder {
7678
self.trigger_call_info();
7779
let snippet = match (ctx.config.add_call_argument_snippets, params) {
7880
(true, Params::Named(params)) => {
79-
let function_params_snippet =
80-
params.iter().enumerate().format_with(", ", |(index, param_name), f| {
81-
f(&format_args!("${{{}:{}}}", index + 1, param_name))
82-
});
81+
let function_params_snippet = params.iter().enumerate().format_with(
82+
", ",
83+
|(index, (param_source, param)), f| {
84+
let name;
85+
let text;
86+
let (ref_, name) = match param_source {
87+
Either::Left(self_param) => (
88+
match self_param.kind() {
89+
ast::SelfParamKind::Owned => "",
90+
ast::SelfParamKind::Ref => "&",
91+
ast::SelfParamKind::MutRef => "&mut ",
92+
},
93+
"self",
94+
),
95+
Either::Right(it) => {
96+
let n = (|| {
97+
let mut pat = it.pat()?;
98+
loop {
99+
match pat {
100+
ast::Pat::IdentPat(pat) => break pat.name(),
101+
ast::Pat::RefPat(it) => pat = it.pat()?,
102+
_ => return None,
103+
}
104+
}
105+
})();
106+
match n {
107+
Some(n) => {
108+
name = n;
109+
text = name.text();
110+
let text = text.as_str().trim_start_matches('_');
111+
let ref_ = ref_of_param(ctx, text, param.ty());
112+
(ref_, text)
113+
}
114+
None => ("", "_"),
115+
}
116+
}
117+
};
118+
f(&format_args!("${{{}:{}{}}}", index + 1, ref_, name))
119+
},
120+
);
83121
format!("{}({})$0", name, function_params_snippet)
84122
}
85123
_ => {
@@ -93,3 +131,13 @@ impl Builder {
93131
self.lookup_by(name).label(label).insert_snippet(cap, snippet)
94132
}
95133
}
134+
fn ref_of_param(ctx: &CompletionContext, arg: &str, ty: &hir::Type) -> &'static str {
135+
if let Some(derefed_ty) = ty.remove_ref() {
136+
for (name, local) in ctx.locals.iter() {
137+
if name.as_text().as_deref() == Some(arg) && local.ty(ctx.db) == derefed_ty {
138+
return if ty.is_mutable_reference() { "&mut " } else { "&" };
139+
}
140+
}
141+
}
142+
""
143+
}

crates/ide_completion/src/render/function.rs

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Renderer for function calls.
22
3+
use either::Either;
34
use hir::{AsAssocItem, HasSource, HirDisplay};
45
use ide_db::SymbolKind;
56
use itertools::Itertools;
@@ -160,47 +161,25 @@ impl<'a> FunctionRender<'a> {
160161
format!("-> {}", ret_ty.display(self.ctx.db()))
161162
}
162163

163-
fn add_arg(&self, arg: &str, ty: &hir::Type) -> String {
164-
if let Some(derefed_ty) = ty.remove_ref() {
165-
for (name, local) in self.ctx.completion.locals.iter() {
166-
if name == arg && local.ty(self.ctx.db()) == derefed_ty {
167-
let mutability = if ty.is_mutable_reference() { "&mut " } else { "&" };
168-
return format!("{}{}", mutability, arg);
169-
}
170-
}
171-
}
172-
arg.to_string()
173-
}
174-
175164
fn params(&self) -> Params {
176165
let ast_params = match self.ast_node.param_list() {
177166
Some(it) => it,
178167
None => return Params::Named(Vec::new()),
179168
};
169+
let params = ast_params.params().map(Either::Right);
180170

181-
let mut params_pats = Vec::new();
182-
let params_ty = if self.ctx.completion.has_dot_receiver() || self.receiver.is_some() {
183-
self.func.method_params(self.ctx.db()).unwrap_or_default()
171+
let params = if self.ctx.completion.has_dot_receiver() || self.receiver.is_some() {
172+
params.zip(self.func.method_params(self.ctx.db()).unwrap_or_default()).collect()
184173
} else {
185-
if let Some(s) = ast_params.self_param() {
186-
cov_mark::hit!(parens_for_method_call_as_assoc_fn);
187-
params_pats.push(Some(s.to_string()));
188-
}
189-
self.func.assoc_fn_params(self.ctx.db())
174+
ast_params
175+
.self_param()
176+
.map(Either::Left)
177+
.into_iter()
178+
.chain(params)
179+
.zip(self.func.assoc_fn_params(self.ctx.db()))
180+
.collect()
190181
};
191-
params_pats
192-
.extend(ast_params.params().into_iter().map(|it| it.pat().map(|it| it.to_string())));
193-
194-
let params = params_pats
195-
.into_iter()
196-
.zip(params_ty)
197-
.flat_map(|(pat, param_ty)| {
198-
let pat = pat?;
199-
let name = pat;
200-
let arg = name.trim_start_matches("mut ").trim_start_matches('_');
201-
Some(self.add_arg(arg, param_ty.ty()))
202-
})
203-
.collect();
182+
204183
Params::Named(params)
205184
}
206185

@@ -310,7 +289,6 @@ impl S {
310289

311290
#[test]
312291
fn parens_for_method_call_as_assoc_fn() {
313-
cov_mark::check!(parens_for_method_call_as_assoc_fn);
314292
check_edit(
315293
"foo",
316294
r#"

0 commit comments

Comments
 (0)