Skip to content

Commit 5d25d24

Browse files
bors[bot]Jonas Schievink
andauthored
Merge #11961
11961: feature: deprioritize already-imported names in `use` items r=jonas-schievink a=jonas-schievink ![screenshot-2022-04-11-18:48:46](https://user-images.githubusercontent.com/1786438/162790376-6b133925-7cf9-46c5-b0e2-d8c3cba61d47.png) Fixes #11640 bors r+ Co-authored-by: Jonas Schievink <[email protected]>
2 parents b1854ce + 63f87ff commit 5d25d24

File tree

8 files changed

+119
-49
lines changed

8 files changed

+119
-49
lines changed

crates/ide_completion/src/completions.rs

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl Completions {
126126
cov_mark::hit!(qualified_path_doc_hidden);
127127
return;
128128
}
129-
self.add(render_resolution(RenderContext::new(ctx), local_name, resolution));
129+
self.add(render_resolution(RenderContext::new(ctx), local_name, resolution).build());
130130
}
131131

132132
pub(crate) fn add_resolution_simple(
@@ -138,7 +138,7 @@ impl Completions {
138138
if ctx.is_scope_def_hidden(resolution) {
139139
return;
140140
}
141-
self.add(render_resolution_simple(RenderContext::new(ctx), local_name, resolution));
141+
self.add(render_resolution_simple(RenderContext::new(ctx), local_name, resolution).build());
142142
}
143143

144144
pub(crate) fn add_macro(
@@ -152,11 +152,14 @@ impl Completions {
152152
Visible::Editable => true,
153153
Visible::No => return,
154154
};
155-
self.add(render_macro(
156-
RenderContext::new(ctx).private_editable(is_private_editable),
157-
local_name,
158-
mac,
159-
));
155+
self.add(
156+
render_macro(
157+
RenderContext::new(ctx).private_editable(is_private_editable),
158+
local_name,
159+
mac,
160+
)
161+
.build(),
162+
);
160163
}
161164

162165
pub(crate) fn add_function(
@@ -170,11 +173,14 @@ impl Completions {
170173
Visible::Editable => true,
171174
Visible::No => return,
172175
};
173-
self.add(render_fn(
174-
RenderContext::new(ctx).private_editable(is_private_editable),
175-
local_name,
176-
func,
177-
));
176+
self.add(
177+
render_fn(
178+
RenderContext::new(ctx).private_editable(is_private_editable),
179+
local_name,
180+
func,
181+
)
182+
.build(),
183+
);
178184
}
179185

180186
pub(crate) fn add_method(
@@ -189,12 +195,15 @@ impl Completions {
189195
Visible::Editable => true,
190196
Visible::No => return,
191197
};
192-
self.add(render_method(
193-
RenderContext::new(ctx).private_editable(is_private_editable),
194-
receiver,
195-
local_name,
196-
func,
197-
));
198+
self.add(
199+
render_method(
200+
RenderContext::new(ctx).private_editable(is_private_editable),
201+
receiver,
202+
local_name,
203+
func,
204+
)
205+
.build(),
206+
);
198207
}
199208

200209
pub(crate) fn add_const(&mut self, ctx: &CompletionContext, konst: hir::Const) {
@@ -235,7 +244,11 @@ impl Completions {
235244
variant: hir::Variant,
236245
path: hir::ModPath,
237246
) {
238-
self.add_opt(render_variant_lit(RenderContext::new(ctx), None, variant, Some(path)));
247+
if let Some(builder) =
248+
render_variant_lit(RenderContext::new(ctx), None, variant, Some(path))
249+
{
250+
self.add(builder.build());
251+
}
239252
}
240253

241254
pub(crate) fn add_enum_variant(
@@ -244,7 +257,11 @@ impl Completions {
244257
variant: hir::Variant,
245258
local_name: Option<hir::Name>,
246259
) {
247-
self.add_opt(render_variant_lit(RenderContext::new(ctx), local_name, variant, None));
260+
if let Some(builder) =
261+
render_variant_lit(RenderContext::new(ctx), local_name, variant, None)
262+
{
263+
self.add(builder.build());
264+
}
248265
}
249266

250267
pub(crate) fn add_field(
@@ -275,8 +292,11 @@ impl Completions {
275292
path: Option<hir::ModPath>,
276293
local_name: Option<hir::Name>,
277294
) {
278-
let item = render_struct_literal(RenderContext::new(ctx), strukt, path, local_name);
279-
self.add_opt(item);
295+
if let Some(builder) =
296+
render_struct_literal(RenderContext::new(ctx), strukt, path, local_name)
297+
{
298+
self.add(builder.build());
299+
}
280300
}
281301

282302
pub(crate) fn add_union_literal(

crates/ide_completion/src/completions/flyimport.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
205205
&user_input_lowercased,
206206
)
207207
})
208-
.filter_map(|import| render_resolution_with_import(RenderContext::new(ctx), import)),
208+
.filter_map(|import| render_resolution_with_import(RenderContext::new(ctx), import))
209+
.map(|builder| builder.build()),
209210
);
210211
Some(())
211212
}

crates/ide_completion/src/completions/use_.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//! Completion for use trees
22
33
use hir::ScopeDef;
4+
use rustc_hash::FxHashSet;
45
use syntax::{ast, AstNode};
56

67
use crate::{
78
context::{CompletionContext, PathCompletionCtx, PathKind, PathQualifierCtx},
8-
Completions,
9+
item::Builder,
10+
CompletionRelevance, Completions,
911
};
1012

1113
pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext) {
@@ -39,6 +41,22 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
3941
None => return,
4042
};
4143

44+
let mut already_imported_names = FxHashSet::default();
45+
if let Some(list) = ctx.token.ancestors().find_map(ast::UseTreeList::cast) {
46+
let use_tree = list.parent_use_tree();
47+
if use_tree.path().as_ref() == Some(path) {
48+
for tree in list.use_trees() {
49+
if tree.is_simple_path() {
50+
if let Some(name) =
51+
tree.path().and_then(|path| path.as_single_name_ref())
52+
{
53+
already_imported_names.insert(name.to_string());
54+
}
55+
}
56+
}
57+
}
58+
}
59+
4260
match resolution {
4361
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
4462
let module_scope = module.scope(ctx.db, Some(ctx.module));
@@ -50,6 +68,9 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
5068
)
5169
};
5270
for (name, def) in module_scope {
71+
let is_name_already_imported =
72+
already_imported_names.contains(name.as_text().unwrap().as_str());
73+
5374
let add_resolution = match def {
5475
ScopeDef::Unknown if unknown_is_current(&name) => {
5576
// for `use self::foo$0`, don't suggest `foo` as a completion
@@ -61,7 +82,12 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
6182
};
6283

6384
if add_resolution {
64-
acc.add_resolution(ctx, name, def);
85+
let mut builder = Builder::from_resolution(ctx, name, def);
86+
builder.set_relevance(CompletionRelevance {
87+
is_name_already_imported,
88+
..Default::default()
89+
});
90+
acc.add(builder.build());
6591
}
6692
}
6793
}

crates/ide_completion/src/item.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ use stdx::{impl_from, never};
99
use syntax::{SmolStr, TextRange};
1010
use text_edit::TextEdit;
1111

12+
use crate::{
13+
context::CompletionContext,
14+
render::{render_resolution, RenderContext},
15+
};
16+
1217
/// `CompletionItem` describes a single completion variant in the editor pop-up.
1318
/// It is basically a POD with various properties. To construct a
1419
/// `CompletionItem`, use `new` method and the `Builder` struct.
@@ -134,6 +139,8 @@ pub struct CompletionRelevance {
134139
pub is_local: bool,
135140
/// This is set when trait items are completed in an impl of that trait.
136141
pub is_item_from_trait: bool,
142+
/// This is set when an import is suggested whose name is already imported.
143+
pub is_name_already_imported: bool,
137144
/// Set for method completions of the `core::ops` and `core::cmp` family.
138145
pub is_op_method: bool,
139146
/// Set for item completions that are private but in the workspace.
@@ -200,6 +207,7 @@ impl CompletionRelevance {
200207
type_match,
201208
is_local,
202209
is_item_from_trait,
210+
is_name_already_imported,
203211
is_op_method,
204212
is_private_editable,
205213
postfix_match,
@@ -214,6 +222,10 @@ impl CompletionRelevance {
214222
if !is_op_method {
215223
score += 10;
216224
}
225+
// lower rank for conflicting import names
226+
if !is_name_already_imported {
227+
score += 1;
228+
}
217229
if exact_name_match {
218230
score += 10;
219231
}
@@ -413,6 +425,14 @@ pub(crate) struct Builder {
413425
}
414426

415427
impl Builder {
428+
pub(crate) fn from_resolution(
429+
ctx: &CompletionContext,
430+
local_name: hir::Name,
431+
resolution: hir::ScopeDef,
432+
) -> Self {
433+
render_resolution(RenderContext::new(ctx), local_name, resolution)
434+
}
435+
416436
pub(crate) fn build(self) -> CompletionItem {
417437
let _p = profile::span("item::Builder::build");
418438

crates/ide_completion/src/render.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use syntax::{SmolStr, SyntaxKind, TextRange};
1818

1919
use crate::{
2020
context::{PathCompletionCtx, PathKind},
21-
item::CompletionRelevanceTypeMatch,
21+
item::{Builder, CompletionRelevanceTypeMatch},
2222
render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
2323
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
2424
};
@@ -144,22 +144,22 @@ pub(crate) fn render_resolution(
144144
ctx: RenderContext<'_>,
145145
local_name: hir::Name,
146146
resolution: ScopeDef,
147-
) -> CompletionItem {
147+
) -> Builder {
148148
render_resolution_(ctx, local_name, None, resolution)
149149
}
150150

151151
pub(crate) fn render_resolution_simple(
152152
ctx: RenderContext<'_>,
153153
local_name: hir::Name,
154154
resolution: ScopeDef,
155-
) -> CompletionItem {
155+
) -> Builder {
156156
render_resolution_simple_(ctx, local_name, None, resolution)
157157
}
158158

159159
pub(crate) fn render_resolution_with_import(
160160
ctx: RenderContext<'_>,
161161
import_edit: LocatedImport,
162-
) -> Option<CompletionItem> {
162+
) -> Option<Builder> {
163163
let resolution = ScopeDef::from(import_edit.original_item);
164164
let local_name = match resolution {
165165
ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
@@ -182,7 +182,7 @@ fn render_resolution_(
182182
local_name: hir::Name,
183183
import_to_add: Option<LocatedImport>,
184184
resolution: ScopeDef,
185-
) -> CompletionItem {
185+
) -> Builder {
186186
let _p = profile::span("render_resolution");
187187
use hir::ModuleDef::*;
188188

@@ -211,7 +211,7 @@ fn render_resolution_simple_(
211211
local_name: hir::Name,
212212
import_to_add: Option<LocatedImport>,
213213
resolution: ScopeDef,
214-
) -> CompletionItem {
214+
) -> Builder {
215215
let _p = profile::span("render_resolution");
216216
use hir::ModuleDef::*;
217217

@@ -292,7 +292,7 @@ fn render_resolution_simple_(
292292
if let Some(import_to_add) = ctx.import_to_add {
293293
item.add_import(import_to_add);
294294
}
295-
item.build()
295+
item
296296
}
297297

298298
fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
@@ -625,6 +625,7 @@ fn main() { let _: m::Spam = S$0 }
625625
),
626626
is_local: false,
627627
is_item_from_trait: false,
628+
is_name_already_imported: false,
628629
is_op_method: false,
629630
is_private_editable: false,
630631
postfix_match: None,
@@ -648,6 +649,7 @@ fn main() { let _: m::Spam = S$0 }
648649
),
649650
is_local: false,
650651
is_item_from_trait: false,
652+
is_name_already_imported: false,
651653
is_op_method: false,
652654
is_private_editable: false,
653655
postfix_match: None,
@@ -737,6 +739,7 @@ fn foo() { A { the$0 } }
737739
),
738740
is_local: false,
739741
is_item_from_trait: false,
742+
is_name_already_imported: false,
740743
is_op_method: false,
741744
is_private_editable: false,
742745
postfix_match: None,

crates/ide_completion/src/render/function.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub(crate) fn render_fn(
2222
ctx: RenderContext<'_>,
2323
local_name: Option<hir::Name>,
2424
func: hir::Function,
25-
) -> CompletionItem {
25+
) -> Builder {
2626
let _p = profile::span("render_fn");
2727
render(ctx, local_name, func, FuncKind::Function)
2828
}
@@ -32,7 +32,7 @@ pub(crate) fn render_method(
3232
receiver: Option<hir::Name>,
3333
local_name: Option<hir::Name>,
3434
func: hir::Function,
35-
) -> CompletionItem {
35+
) -> Builder {
3636
let _p = profile::span("render_method");
3737
render(ctx, local_name, func, FuncKind::Method(receiver))
3838
}
@@ -42,7 +42,7 @@ fn render(
4242
local_name: Option<hir::Name>,
4343
func: hir::Function,
4444
func_kind: FuncKind,
45-
) -> CompletionItem {
45+
) -> Builder {
4646
let db = completion.db;
4747

4848
let name = local_name.unwrap_or_else(|| func.name(db));
@@ -107,7 +107,7 @@ fn render(
107107
}
108108
}
109109
}
110-
item.build()
110+
item
111111
}
112112

113113
pub(super) fn add_call_parens<'b>(

0 commit comments

Comments
 (0)